简体   繁体   English

Node JS + Passport 登录

[英]Node JS + Passport login

I'm trying to configure my first node js app to login using passport.我正在尝试将我的第一个节点 js 应用程序配置为使用通行证登录。

So first things first.所以首先要做的事情。 I create a /app/config/express.js file to configure express stuff.我创建了一个/app/config/express.js文件来配置 express 的东西。 So my app.js is simpler:所以我的app.js更简单:

var app = require('./app/config/express')();

app.listen(3001, function(){
    console.log("Servidor rodando");
});

Ok... that's cool.好,这很酷。 BUT!但! My express.js file is too big.我的 express.js 文件太大了。 Maybe you can give me some tips on how to refactor this?也许你可以给我一些关于如何重构它的提示?

I added some comments with some questions that I would love to make this code better.我添加了一些带有一些问题的评论,我很乐意让这段代码变得更好。

var express = require('express');
var load = require('express-load');
var expressValidator = require('express-validator');
var bodyParser = require('body-parser');
var passport = require('passport');
var Strategy = require('passport-local').Strategy;
var session = require('express-session');
var flash = require("connect-flash");

module.exports = function() {

    // PLEASE READ 1
    //
    // 
    // Functions to organize code better.
    // PS: if this functions are outside "module.exports", then Express
    // doesnt 'inject' the 'app.infra' variable .... 
    // Is there a workaround to move these functions outta here?
    //
    // 
    function configureAuth(){
        passport.use(new Strategy({
            passReqToCallback : true
          },
          function(req, username, password, cb) {

            var connection = app.infra.connectionFactory();
            var userDao = new app.infra.dao.UserDao(connection);

            userDao.login(username, password, function(err, user){
              if (err) {
                return cb(err);
              }

              if (!user) {
                return cb(null, false);
              }


              return cb(null, user);
            });

            connection.end();

          }));

        //
        // 
        // HERE IT IS!
        //
        //
        passport.serializeUser(function(user, cb) {
          cb(null, user.id);
        });

        passport.deserializeUser(function(id, cb) {
            cb(null, user);
        });
    }

    function configureExpressLibs(app){
        app.set('view engine', 'ejs');
        app.set('views','./app/views');

        app.use('/static', express.static('./app/public'));
        app.use(flash());

        app.use(bodyParser.urlencoded({extended: true}));
        app.use(bodyParser.json());
        app.use(expressValidator());

        app.use(session({
            secret: '086this 54is 23unkowned 67',
            resave: false,
            saveUninitialized: false
        }));

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

    function configureErrors(app){
        app.use(function(err, req, res, next) {
            console.error(err.stack)
            next(err)
        });

        app.use(function(req,res,next){
            res.status(404).render('errors/404');
            next();
        });


        app.use(function(error, req,res,next){
            res.status(500).render('errors/500');
            next();
        });
    }

     // PLEASE READ 2
     // 
     // 
     //  I've moved this to 'LoginController.js' in my routes folder but
     //  I didnt work... So I moved it here. Is there a work around?
     //
     //
    function configureLoginRoutes(app){

      function redirectToIndexIfLoggedIn(req, res, next) {
        if (req.isAuthenticated())
          res.redirect('/');

        return next();
      }

      app.get('/login', redirectToIndexIfLoggedIn, function(req, res){
        res.render('login/login');
      });

      app.post('/login', passport.authenticate('local', {
        successRedirect : '/',
        failureRedirect : '/login',
        failureFlash : 'Invalid username or password.'
        }));

      app.get('/logout', function(req, res){
          req.logout();
          req.session.destroy();
          res.redirect('/');
      });
    }


    var app = express();

    configureExpressLibs(app);

    configureAuth();

    configureLoginRoutes(app);


    load('routes',{cwd: 'app'})
        .then('infra')
        .into(app);

    configureErrors(app);

    return app;
}

So the problem now is, when I login (it doesnt matter if the user is correct or wrong), I get a:所以现在的问题是,当我登录时(用户正确或错误无关紧要),我得到:

Error: Failed to serialize user into session

I googled it and saw the the reason for this is because people forgot to implement "serializeUser".我用谷歌搜索了一下,发现原因是人们忘记了实现“serializeUser”。 But I did.但我做到了。 Please check the comment with "HERE IT IS" on the code above.请检查上面代码中带有“这里是”的注释。

Thanks guys.谢谢你们。 Sorry for the big code.对不起,大代码。 But I'm learning and I hope to make things better with your help.但我正在学习,我希望在你的帮助下让事情变得更好。

EDIT My deserialize method was wrong.编辑我的反序列化方法是错误的。 I fixed it using:我使用以下方法修复它:

    passport.deserializeUser(function(id, cb) {
      var connection = app.infra.connectionFactory();
      var userDao = new app.infra.dao.UserDao(connection);

      userDao.findById(id, function(err, user) {
        done(err, user);
      });

      connection.end();

    });

but the application still fails.但应用程序仍然失败。 Same error.同样的错误。

EDIT SOLUTION编辑解决方案

Turns out my implementation was wrong.原来我的实现是错误的。 You see, mysql always returns an array.你看,mysql 总是返回一个数组。 Thus I corrected my code like this:因此,我像这样更正了我的代码:

      function(req, username, password, cb) {

        var connection = app.infra.connectionFactory();
        var userDao = new app.infra.dao.UserDao(connection);

        userDao.login(username, password, function(err, user){
          if (err) {
            return cb(err);
          }

          if (!user) {
            return cb(null, false);
          }

          // HERE

          return cb(null, user[0]);
        });

        connection.end();

      }));

And here:和这里:

    passport.deserializeUser(function(id, cb) {
      var connection = app.infra.connectionFactory();
      var userDao = new app.infra.dao.UserDao(connection);

      userDao.findById(id, function(err, user) {
         // HERE
         cb(err, user[0]);
      });

      connection.end();

    });
} 

I think your this.user is not setting inside deserializeUser when you call cb(null,user) so create your own middleware after app.use(passport.session()) to put it in this.user like so:我认为当您调用cb(null,user)时,您的 this.user 没有设置在 deserializeUser 中cb(null,user)因此在 app.use(passport.session()) 之后创建您自己的中间件以将其放入this.user如下所示:

app.use(function * setUserInContext (next) {
  this.user = this.req.user
  yield next
})

Cheers :)干杯:)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM