我在应用程序中使用Passport进行身份验证,并且还在使用Express。概括一下我的问题: 我的登录功能最初运行良好,但是在 任何 用户的会话超时后, 没有 用户可以登录。
我正在使用标准的本地策略进行身份验证。
我将根据自己的设置提供一个尽可能简单的示例:
//------------- //Set up authentication with Passport //------------- var userModel = require('./models/user')(db); passport.use(new LocalStrategy( function(username, password, done) { var errorMessage = 'Incorrect username/password combination.'; userModel.GetUserByUsername(username, function(err, user) { if (err) { return done(err); } if (!user) { return done(null, false, { message: errorMessage }); } user.validatePassword(password, function(isPasswordCorrect) { if (!isPasswordCorrect) { return done(null, false, { message: errorMessage }); } //Update with login date userModel.UpdateUserWithLogin(username, user.currentLoginTime, function(err){ //if we have an error here, we should probably just log it if(err) { console.log(err); } }); return done(null, user); }); }); } )); passport.serializeUser(function(user, done) { done(null, user); }); passport.deserializeUser(function(user, done) { userModel.GetUserByUsername(user._id, function(err, user) { done(err, user); }); }); //------------- //Set up express and configure //------------- var sessionStore = new SkinStore(db); var app = express(); app.configure(function(){ app.set('port', process.env.PORT || 3000); app.set('views', __dirname + '/views'); app.engine('html', consolidate.swig); app.set('view engine', 'html'); swig.init({ root: '.', allowErrors: true, // allows errors to be thrown and caught by express instead of suppressed autoescape: false}); app.use(express.logger('dev')); app.use(express.bodyParser()); app.use(express.methodOverride()); app.use(express.cookieParser("[mysecrethere]")); app.use(express.session({ store: sessionStore, cookie: { expires : new Date(Date.now() + 3600000) } //1 Hour })); app.use(passport.initialize()); app.use(passport.session()); app.use(flash()); app.use(expressValidator); app.use(express.static(path.join(__dirname, 'public'))); //Dynamic helpers app.use(require('./helpers/DynamicHelpers')); app.use(app.router); }); app.get('/login', routes.login); app.post('/login', passport.authenticate('local', {failureRedirect: '/login', badRequestMessage: "Please enter username and password", failureFlash: true }), function(req, res) { var targetUrl = req.session.pageAfterLogin; delete req.session.pageAfterLogin; res.redirect(targetUrl || '/account'); }); app.get('/account', IsAuthenticated, routes.account.show);
和IsAuthenticated辅助函数:
function IsAuthenticated(req,res,next){ if(req.isAuthenticated()) { next(); } else { //save the requested page and then redirected req.session.pageAfterLogin = req.url; req.flash("error", "You must be logged in first!"); res.redirect('/login'); } }
通过调试可以找到的是,在成功进行身份验证之后(cookie过期之后),我击中了这个逻辑(从上面):
function(req, res) { var targetUrl = req.session.pageAfterLogin; delete req.session.pageAfterLogin; res.redirect(targetUrl || '/account'); }
我可以在其中看到“ req”已正确设置了会话,并正确存储了Passport信息。然后,发生重定向, 新 请求没有存储会话信息,并且具有全新的会话ID。我怀疑没有在客户端上设置cookie,事实确实如此,这应该可以解释缺少一致的会话的原因。
但是,我无法弄清楚 为什么 没有设置新的cookie。应用程序的配置方式是否有问题,以表明发生这种情况的原因?
我应该补充一点,重新启动Node.js实例可以解决此问题,但这并不是生产中可以容忍的。
谢谢。
更新 :我运行了Fiddler,以查看HTTP / S流量发生了什么,我可以看到,最初运行时,我在浏览器中设置了一个cookie(我尝试了几次),然后将该cookie传递回服务器。后续请求。
当它 不起作用时 ,浏览器不会将cookie传递到服务器,因此Node会发送Set- Cookie标头,该标头每次提供一个新的cookie。到目前为止,我还没有运气确定原因。
我弄清楚了,尽管我不喜欢这个答案。
tl; dr; -使用maxAge而不是过期。
问题的根源是在每个Cookie上设置的到期日期(由Express自动设置)。我注意到,每个设置的Cookie都具有相同的到期日期,最终该到期日期是过去的日期,因此立即到期。
原因在这里:
cookie: { expires : new Date(Date.now() + 3600000) }
服务器启动后,仅创建一次新的日期。这导致到期时间每次都相同。根据原始帖子中的代码,我无法弄清楚为什么它不起作用,但是我在网上找到的每个示例都使用完全相同的代码。我通过定义一个创建此Date的函数并检查它是否仅在服务器启动时被调用来验证这一点。
为了解决此问题,我定义了maxAge而不是“ expires”。maxAge需要花费毫秒数而不是日期,并且似乎正确设置了所有cookie的到期日期。
我很想听听是否有人可以一开始就解释为什么会这样,因为其他人似乎已经成功地使用了它。 有什么想法吗?
请参阅下面的工作代码
app.configure(function(){ app.set('port', process.env.PORT || 3000); app.set('views', __dirname + '/views'); app.engine('html', consolidate.swig); app.set('view engine', 'html'); swig.init({ root: '.', allowErrors: true, // allows errors to be thrown and caught by express instead of suppressed autoescape: false}); app.use(express.logger('dev')); app.use(express.bodyParser()); app.use(express.methodOverride()); app.use(express.cookieParser("[mysecrethere]")); app.use(express.session({ store: sessionStore, cookie: { maxAge : 3600000 } //1 Hour })); app.use(passport.initialize()); app.use(passport.session()); app.use(flash()); app.use(expressValidator); app.use(express.static(path.join(__dirname, 'public'))); //Dynamic helpers app.use(require('./helpers/DynamicHelpers')); app.use(app.router); });