Node.js Express护照Cookie过期

我在我的应用程序中使用Passport进行身份validation,而且我也使用Express。 总结我的问题: 我的loginfunction最初工作正常,但在任何用户会话超时后,用户无法login。

我正在使用标准的本地策略进行身份validation。

根据我的设置,我将尽可能包含一个示例:

//------------- //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'); } } 

我可以通过debuggingfind的是,成功的身份validation(和一个cookie已过期后),我打这个逻辑(从上面):

 function(req, res) { var targetUrl = req.session.pageAfterLogin; delete req.session.pageAfterLogin; res.redirect(targetUrl || '/account'); } 

在哪里我可以看到“req”会话正确设置,Passport信息正确存储。 然后,redirect发生, 请求没有存储会话信息,并具有全新的会话ID。 我怀疑客户端没有设置cookie,而且确实如此,这应该解释为什么没有一致的会话。

但是,我不明白为什么没有新的cookie被设置。 应用程序的configuration方式有什么问题,这将说明为什么会发生这种情况?

我应该补充一点,重新启动Node.js实例可以解决问题,这只是在生产中不能容忍的东西。

谢谢。

更新 :我跑Fiddler,看看发生了什么HTTP / Sstream量,我可以看到,当它最初工作时,我得到一个cookie设置在浏览器(我试了几个),然后传回到服务器上随后的请求。

当它不起作用时 ,浏览器不会传递cookie到服务器,所以Node发送一个Set-Cookie头,每次都提供一个新的cookie。 到目前为止,我没有运气确定这个原因。

我知道了,尽pipe我不喜欢答案。

TL;博士; – 使用maxAge而不是过期。


问题的根源在于每个cookie(由Express自动设置)设置的到期date。 我注意到,每个设置的cookie都有相同的截止date,最终结束于过去,因此立即过期。

原因是在这里:

 cookie: { expires : new Date(Date.now() + 3600000) } 

新的date在服务器启动时只创build一次。 这是导致到期date每次都是一样的。 根据原来的post中的代码,我不知道为什么它不工作,但我在网上find的每个例子使用完全相同的代码。 我通过定义一个创build这个Date的函数来validation这一点,并检查它只在服务器启动时被调用。

要解决这个问题,我正在定义maxAge而不是“expires”。 maxAge需要几毫秒,而不是一个date,它似乎是正确设置所有cookie的到期date。

我很想听听有没有人可以解释为什么这是首先发生,因为其他人似乎成功地使用它。 有什么想法吗?

见下面我的工作代码

 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); }); 

将cookie名称设置为value,其中可能是string或转换为JSON的对象。 path选项默认为“/”。

res.cookie('rememberme', '1', { expires: new Date(Date.now() + 900000), httpOnly: true });

maxAge选项是一个方便的选项,用于设置相对于当前时间的“过期”(以毫秒为单位)。 以下相当于前面的例子。

res.cookie('rememberme', '1', { maxAge: 900000, httpOnly: true })

也链接

http://expressjs.com/api.html#res.cookie