@nurzhannogerbek

Как создать правильную систему авторизации?

Здравствуйте, товарищи! Помогите пожалуйста разобраться. Хочу понять последовательность действий.

На стеке Node.js + Express.js + Vue.js + PostgreSQL пытаюсь создать проект. Суть проекта простая, пользователь заходит на сайт. Если до этого он не был авторизован, то его встречает страница авторизации. После авторизации пользователь попадает на главную страницу. На главной странице в зависимости от роли пользователя нужно показать разные сообщения.

Прочитал очень много материала на тематику авторизации после которых каша в голове связанная с токенами. В основном многие статьи связаны с MongoDB. Я не совсем понял какой best practice и как лучше всего все построить. К примеру в Node.js лучше подключиться к PostgreSQL базе данных через пакет node-postgres или через ORM общаться (пакет sequelize)? В случаи первого пакета, я создаю пул и выполняю нативные SQL запросы. В случаи второго пакета, нужно создавать модель данных (model) и контактировать с ней.

Если встречали готовые решения или хорошие статьи на эту тему был бы рад на них взглянуть.
  • Вопрос задан
  • 4333 просмотра
Пригласить эксперта
Ответы на вопрос 3
@antimodern
каша в голове связанная с токенами


Хорошо что ты это понимаешь. Небось как и все нубасики начитался прплаченных статеек от Auth0 и Firebase? Ну так каша специально, чтобы ты к ним побежал делать эти токены) Маркетинг. Хайп.

Второй шаг - не использовать токены для авторизации (как это делают ВСЕ реальные проекты, а не Hello World туториалы). Вместо токенов - обычные сессии. Токены - если будет публичный апи и микросервисы.

Третий шаг - не использовать Паспорт. Зачем он нужен если есть express-session, не понимаю? Паспорт юзай только если будешь прикручивать несколько авторизаций социалок и времени вообще впритык. И то лучше самому и это сделать.
Ответ написан
MDiMaI666
@MDiMaI666
Талантливый программист
// pgsql + sequelize + passport
// sessions will save in DB, after restart app entirel will save
// http://docs.sequelizejs.com

//////////////////////////////////////
//APP.js
const session = require('express-session');
const pgSession = require('connect-pg-simple')(session);
const pg = require('pg');
var passport = require('passport');
//sequelizejs - not necessary

// ... After
// app.use(bodyParser.json());
// app.use(cookieParser());
// ...


// native postgress client
var pgPool = new pg.Pool(Object.assign(config_db, {user: config_db.username}) );
// https://github.com/voxpelli/node-connect-pg-simple
app.use(session({
  store: new pgSession({
    pool : pgPool,                // Connection pool
    tableName : 'sessions'   // Use another table-name than the default "session" one
  }),
  secret: process.env.FOO_COOKIE_SECRET || 'oU80saf_Dwd48w9',
  resave: true,
  saveUninitialized: true,
  cookie: { maxAge: 7 * 24 * 60 * 60 * 1000 } // 7 days
}));


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

require('./routes/auth')(app,passport); // !!! this file in below


//////////////////////////////////////
// /routes/auth.js
//http://www.passportjs.org/docs/username-password/
const flash = require("connect-flash"); //https://www.npmjs.com/package/connect-flash cross redirect messages
var LocalStrategy = require('passport-local').Strategy;

function AUTH(app, passport){

  app.use(flash());
  
  passport.use(new LocalStrategy({
      usernameField: 'email',
      passwordField: 'password',
      passReqToCallback: true
    },
    async(req, username, password, done) =>{
  
      try{
        let user = await Users.Login(username, password); //Model Method
  
        if(!user){
          return done(null, false, { message1: 'Incorrect username or password.' });
        } else {
          //if auth
          return done(null, user);
        }
      } catch(ex){
        // return done(err); 
        return done(null, false, { message1: 'Incorrect data.' + ex.message });
      }
    }
  ));
  
  
  //new update
  app.post('/auth/login', function(req, res, next) {
    passport.authenticate('local', function(err, user, info) {
      if (err) { return next(err) }
      if (!user) {
        // *** Display message using Express 3 locals
        req.session.message = (info && info.message) || '';
        return res.redirect('/auth/?returnurl='+req.path);
      }
      //TODO: return url after relogin
      req.logIn(user, function(err) {
        if (err) { return next(err); }
        return res.redirect('/' + (req.query.returnurl || '') );
      });
    })(req, res, next);
  });
  
  //если просто зашли, перенаправить
  app.get('/auth/login', function(req,res,next){
    res.redirect('/auth/');
  });

  app.all('/auth/logout', function(req, res){
    req.logout();
    res.redirect('/auth/');
  });
  
  passport.serializeUser(function(user, done) {
    // done(null, user.id); //VARIANT 1
    done(null, user); //VARIANT 2
  });
  
  // passport.deserializeUser(function(id, done) { //VARIANT 1
  passport.deserializeUser(function(user, done) { //VARIANT 2
    // console.log('Deserialize user called.');
    let incapsuledUserData = {
      id: user.id,
      email: user.email,
      username: user.username,
      fullname: user.fullname,
    };

    global.user = { user: incapsuledUserData };
    return done(null, { user: incapsuledUserData });
  });
  ///
  
  //my
  app.use(function(req, res, next) {
    var isAuthPage = req.path.startsWith('/auth');
    var isApi = req.path.startsWith('/api/');
    
    if (isAuthPage || req.user || isApi) {
      // logged in
      return next(); 
    } else {
      // not logged in
      res.redirect('/auth/?returnurl='+req.path);
    }
  });

  ////////////////AUTH END

}

module.exports = AUTH;


///////////////////////////////////////
// Session Model
// http://docs.sequelizejs.com
sid = { type: Sequelize.STRING, allowNull: false, primaryKey: true };
sess = { type: Sequelize.JSON, allowNull: false };
expire = { type: Sequelize.DATE, allowNull: false };

///////////////////////////////////////
// Optional in API router
router.use(function(req,res,next){

    var haveToken = false;
    var isAllowedForUnauth = false;
    var tokens = [
        'q38ru8Jsd09_we0)weW', 
        //...
    ];

    var allowedPaths = [
        '/letters/feedback',
    ];

    var givedToken = req.headers.token || req.query.token;

    if(tokens.indexOf(givedToken)!==-1)
    haveToken = true;

    if(allowedPaths.indexOf(req.path)!==-1)
    isAllowedForUnauth = true;

    if(req.user || haveToken || isAllowedForUnauth)
        next();
    else {
        res.status(401).send('Access denied');
    }
    
});
Ответ написан
Комментировать
Xuxicheta
@Xuxicheta
инженер
Вы пытаетесь откусить слишком большой кусок пирога. Определитесь что вы хотите изучить, node, postgres или vue? Для общения с бд я бы не рекомендовал сразу использовать sequelize, разберитесь сначала с базовыми CRUD операциями на sql запросах, это не сложно. Въехать в sequelize проще, если понимаете поверх чего эта надстройка.

Для авторизации - сессии, для фронтенда - любой шаблонизатор. А работу в паре с vue начинать, когда с экспрессом уже будет более менее все понятно.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы