我在我的应用程序中使用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');
}
我可以看到&#34; req&#34;正确设置会话,并正确存储Passport信息。然后,重定向发生,新请求没有存储会话信息,并且具有全新的会话ID。我怀疑客户端没有设置cookie,而且确实如此,这可以解释缺乏一致的会话。
但是,我无法弄清楚为什么没有设置新的Cookie。应用程序的配置方式是否有问题可以说明为什么会发生这种情况?
我应该补充一点,重新启动Node.js实例可以解决问题,它不是生产中可以容忍的东西。
感谢。
更新:我运行了Fiddler,看看HTTP / S流量发生了什么,我可以看到,当它最初工作时,我在浏览器中设置了一个cookie(我尝试了几次)然后在随后的请求中传回服务器。
当没有工作时,浏览器不会将Cookie传递给服务器,因此Node会发送每次都提供新Cookie的Set-Cookie标头。到目前为止,我没有运气确定原因。
答案 0 :(得分:25)
我想通了,虽然我不喜欢这个答案。
TL;博士; - 使用maxAge而不是expires。
问题根源于每个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);
});
答案 1 :(得分:-2)
将cookie名称设置为value,其中可以是转换为JSON的字符串或对象。 path选项默认为“/”。
res.cookie('rememberme', '1', { expires: new Date(Date.now() + 900000), httpOnly: true });
maxAge选项是一个方便的选项,用于设置相对于当前时间的“过期”(以毫秒为单位)。以下内容与前面的示例等效。
res.cookie('rememberme', '1', { maxAge: 900000, httpOnly: true })
也是链接