passportJS serializeUser 和 deserializeUser 从未调用过

passportJS serializeUser and deserializeUser never called

我想弄清楚我在这里做错了什么。在查看文档(遗憾的是已经过时)并搜索网络后,我相信我已经正确配置了护照的所有内容,但由于某种原因,serializeUser 和 deserializeUser 都没有被调用,这导致 req.user 从未被设置。

好的,这是我的根 server.js 文件(摘要)

/**
 * Module dependencies
 */

var express = require('express'),
    app = module.exports = express(),
    bodyParser = require('body-parser'),
    cookieParser = require('cookie-parser'),
    env = process.env.NODE_ENV || 'development',
    errorHandler = require('errorhandler'),
    http = require('http'),
    methodOverride = require('method-override'),
    morgan = require('morgan'),
    passport = require('passport'),
    path = require('path'),
    routes = require('./server/routes/index'),
    secret = process.env.SESSION_SECRET,
    session = require('express-session'),
    FileStore = require('session-file-store')(session);

/**
 * Configuration
 */

// all environments
app.set('http-port', process.env.PORT || 3000);
app.set('views', __dirname + '/public');
app.engine('.html', require('ejs').renderFile);
app.use(morgan('dev'));
app.use(methodOverride());
app.use(express.static(path.join(__dirname, 'public')));
app.use(cookieParser(secret));
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());

// development enviornment only
if (env === 'development') {
  app.use(session({ 
    cookie: { maxAge: (60 * 60 * 10) }, // User session will expire after 60     minutes.
    resave: false,
    saveUninitialized: false,
    secret: secret,
  }));
  app.use(errorHandler());
}

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

/**
 * Routes
 */

routes.SESSION_SECRET = secret; // Set env var for the router;
app.use('/', routes); // Handle defined routes
app.get('/', routes.index); // Serve index
app.get('*', routes.index); // Redirect all others to the index (HTML5 history)

/**
 * Start Server
 */

var httpServer = http.createServer(app);
httpServer.listen(app.get('http-port'), function () {
  console.log('Express http server listening on port ' + app.get('http-port'));
});

您会注意到上面的这一行:

routes = require('./server/routes/index'),

这是路由文件(摘要):

var express = require('express');
var router = express.Router();
var auth = require('./modules/auth');

// AUTH ROUTES
router.post('/login', auth.login); // Log a local user into the application     using passport
router.post('/ldap-login', auth.ldapLogin); // Log a LDAP user into the     application using passport
router.get('/logout', auth.logout); // Log the current user out of the system
router.get('/isLoggedIn', auth.isLoggedIn); // Check is the user is logged in
router.post('/updatePassword', auth.updatePassword); // Updates a users password

您会再次注意到此引用:

var auth = require('./modules/auth');

这是 auth 模块(总结)。

'use strict'
var passport = require('passport');
var secret = process.env.SESSION_SECRET;
var crypto = require('../../crypto');
var models = require('../../models');
var User = models.User;

require('../../passport');

// Log a local user into the application using passport
exports.login = function(req, res, next) {
  passport.authenticate('local', function(err, user, info) {
    if(err) { return next(err); }

    if(user) {
      User.find({
        where: {
          email: user.email
        }
      })
      .then(function(currentUser) {
        if(currentUser) {
          currentUser.updateAttributes({
            last_login: new Date()
          });
        }
      });
      user.email = crypto.decrypt(user.email);
      user.first_name = crypto.decrypt(user.first_name);
      user.last_name = crypto.decrypt(user.last_name);
      return res.json({ token: user.generateJWT(secret) });
    } else {
      return res.status(401).json(info);
    }
  })(req, res, next);  
}

在该文件中,我引用了我的护照配置,其中包含我希望达到的功能。

require('../../passport');

这是此处引用的护照配置(摘要)。

(function() {
  var models = require('./models');
  var User = models.User;

  /**
   * Passport authentication
   */
  var passport = require('passport');

  // Passport Local Strategy
  var locStrategy = require('passport-local').Strategy;

  passport.use(new locStrategy({
      usernameField: 'username'
    },
    function(username, password, done) {
      User.find({
        where: {
          username: username
        }
      })
      .then(function(user) {
        if(!user) {
          console.log('No such user found');
          return done(null, false);
        }
        user.verifyPassword(password, function(err, isMatch) {
          if(err) {
            console.log('Error checking password. Error: ' + err);
            return done(err);
          } else if(!isMatch) {
            // Password did not match
            console.log('Passwords did not match');
            return done(null, false);
          } else {
            // Success
            console.log('User logged in');
            return done(null, user);
          }
        });      
      })
      .catch(function(err) {
        console.log('Error logging user in. Message: ' + err);
        return done(err);
      });
    }
  ));

  passport.serializeUser(function(user, done) {
    console.log('serializeUser'); // I expect this to be logged
    done(null, user);
  });

  passport.deserializeUser(function(user, done) {
    console.log('deserializeUser'); // I expect this to be logged
    done(null, user);
  });

  exports.isAuthenticated = passport.authenticate(['local', 'ldapauth']);
})();

您会注意到那里对用户模型的引用,但由于它工作正常,我不会包含任何代码。

我不确定这里有什么问题阻止我使用上面的 passport.serializeUser 和 passport.deserializeUser 方法。我想我可能需要将这些方法包含在 server.js 根目录中,所以我尝试将这些方法移动到 session({}) 配置上方和 passport.session() 调用之后,但都没有任何影响.

找到问题了,希望能帮到别人。

要调用 deserializeUser,您需要在 passport.authenticate() 解析后手动调用 req.login()。我没有这样做,因为在 Passport 文档中它说:

"Note: passport.authenticate() middleware invokes req.login() automatically." 

至少对我来说,passport 应该调用 login,然后在调用 passport.authenticate() 时自动反序列化用户,但这是不正确的。

这是我上面的身份验证模块中的更新代码:

exports.login = function(req, res, next) {
  passport.authenticate('local', function(err, user, info) {
    if(err) { return next(err); }

    if(user) {
      User.find({
        where: {
          email: user.email
        }
      })
      .then(function(currentUser) {
        if(currentUser) {
          currentUser.updateAttributes({
            last_login: new Date()
          })
        }
      });
      user.email = crypto.decrypt(user.email);
      user.first_name = crypto.decrypt(user.first_name);
      user.last_name = crypto.decrypt(user.last_name);
      req.login(user, function(err) { // I added req.login() here and now deserializeUser is being called and req.user is being set correctly.
        if(err) {
          return res.status(401).json(err);
        } else {
          return res.json({ token: user.generateJWT(secret) });
        }
      });
    } else {
      return res.status(401).json(info);
    }
  })(req, res, next);  
}