Как решить проблему с авторизацией на node js и mongoDB?

Для решения проблемы с авторизацией на Node.js с использованием MongoDB можно использовать различные подходы в зависимости от требований вашего проекта. В этом ответе я расскажу о двух популярных способах: использование библиотеки Passport.js и ручная реализация аутентификации и авторизации.

1. Использование библиотеки Passport.js:
Passport.js является популярной библиотекой для аутентификации на Node.js. Она предоставляет различные стратегии аутентификации, включая локальную (используя базу данных MongoDB), OAuth и другие. Процесс решения проблемы авторизации с использованием Passport.js может быть разделен на следующие шаги:

Шаг 1: Установка зависимостей:

   npm install passport passport-local bcryptjs express-session connect-flash

Шаг 2: Инициализация Passport и настройка сессий:

   const passport = require('passport');
   const session = require('express-session');
   const flash = require('connect-flash');

   app.use(session({
     secret: 'your-secret-key',
     resave: true,
     saveUninitialized: true
   }));

   app.use(passport.initialize());
   app.use(passport.session());
   app.use(flash());

Шаг 3: Настройка модели пользователя и маршрутов аутентификации:

   const mongoose = require('mongoose');
   const bcrypt = require('bcryptjs');
   const LocalStrategy = require('passport-local').Strategy;

   const User = mongoose.model('User');

   passport.use(new LocalStrategy({
     usernameField: 'email',
     passwordField: 'password'
   }, (email, password, done) => {
     User.findOne({ email: email })
       .then(user => {
         if (!user) {
           return done(null, false, { message: 'Неверный email.' });
         }
         bcrypt.compare(password, user.password, (err, isMatch) => {
           if (err) throw err;
           if (isMatch) {
             return done(null, user);
           } else {
             return done(null, false, { message: 'Неверный пароль.' });
           }
         });
       })
       .catch(err => console.log(err));
   }));

   passport.serializeUser((user, done) => {
     done(null, user.id);
   });

   passport.deserializeUser((id, done) => {
     User.findById(id, (err, user) => {
       done(err, user);
     });
   });

   app.post('/login', passport.authenticate('local', {
     successRedirect: '/profile',
     failureRedirect: '/login',
     failureFlash: true
   }));

   app.get('/logout', (req, res) => {
     req.logout();
     res.redirect('/');
   });

Шаг 4: Защита маршрутов:

   function ensureAuthenticated(req, res, next) {
     if (req.isAuthenticated()) {
       return next();
     }
     res.redirect('/login');
   }

Данный подход предоставляет готовые аутентификационные и авторизационные механизмы, к которым можно добавить роли и разрешения пользователей в зависимости от требований вашего проекта.

2. Ручная реализация аутентификации и авторизации:
Если вам необходимо больше гибкости и полного контроля над аутентификацией и авторизацией, вы можете реализовать их самостоятельно. В этом случае, вам понадобится:

- Создать модель пользователя и хранить информацию о нем в базе данных MongoDB.
- Реализовать логику регистрации и аутентификации, проверяя соответствие email и пароля пользовательским данным, хранящимся в MongoDB.
- Создать маршруты для регистрации, аутентификации и выхода из системы.
- Защитить маршруты, которые требуют аутентификации, с помощью middleware.

Пример кода для этого подхода выглядит следующим образом:

   const bcrypt = require('bcryptjs');
   const User = require('./models/User');

   // Регистрация пользователя
   app.post('/register', async (req, res) => {
     try {
       const { email, password } = req.body;
       const hashedPassword = await bcrypt.hash(password, 10);
       const user = new User({ email, password: hashedPassword });
       await user.save();
       res.redirect('/login');
     } catch (error) {
       console.log(error);
       res.redirect('/register');
     }
   });

   // Аутентификация пользователя
   app.post('/login', async (req, res) => {
     try {
       const { email, password } = req.body;
       const user = await User.findOne({ email });
       if (!user) {
         res.redirect('/login');
         return;
       }
       const isMatch = await bcrypt.compare(password, user.password);
       if (!isMatch) {
         res.redirect('/login');
         return;
       }
       req.session.user = user;
       res.redirect('/profile');
     } catch (error) {
       console.log(error);
       res.redirect('/login');
     }
   });

   // Выход из системы
   app.get('/logout', (req, res) => {
     req.session.destroy();
     res.redirect('/');
   });

   // Защита маршрутов, требующих авторизацию
   app.get('/profile', (req, res) => {
     if (!req.session.user) {
       res.redirect('/login');
       return;
     }
     res.render('profile', { user: req.session.user });
   });

Этот подход дает вам полный контроль над логикой аутентификации и авторизации, но требует более тщательного и полного написания кода.

Выбор между использованием библиотеки Passport.js и ручной реализацией зависит от сложности и требований вашего проекта. Passport.js предоставляет готовые решения, которые можно быстро интегрировать в проект, в то время как ручная реализация обеспечивает более гибкую адаптацию к уникальным требованиям вашего проекта.