简体   繁体   English

Node.js Express Passport Cookie到期

[英]Node.js Express Passport Cookie Expiration

I am using Passport for authentication in my app, and I am also using Express. 我在我的应用程序中使用Passport进行身份验证,我也在使用Express。 To summarize my issue: my login functionality works fine initially, but after any user's session times out, no users are able to log in. 总结一下我的问题: 我的登录功能最初工作正常,但在任何用户的会话超时后, 没有用户能够登录。

I am using the standard Local strategy for authentication. 我使用标准的本地策略进行身份验证。

I'll include as bare an example as possible based on my setup: 我会根据我的设置尽可能包含一个例子:

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

And the IsAuthenticated helper function: 和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');
    }
}

What I can find by debugging is that, after successful authentication (and after a cookie has expired), I hit this logic (from above): 通过调试我可以找到的是,在成功验证后(以及cookie过期后),我点击了这个逻辑(从上面):

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

Where I can see that the "req" has the session properly set, with Passport information stored properly. 我可以看到“req”正确设置了会话,并正确存储了Passport信息。 Then, the redirect happens, the new request has no session information stored, and has an entirely new Session ID. 然后,重定向发生, 请求没有存储会话信息,并且具有全新的会话ID。 I suspected that no cookie was being set on the client, and that does appear to be the case, which should explain the lack of consistent sessions. 我怀疑客户端没有设置cookie,这似乎确实如此,这可以解释缺乏一致的会话。

However, I cannot figure out why no new cookie is being set. 但是,我无法弄清楚为什么没有设置新的cookie。 Is there something wrong with how the app is configured that would indicate why this is happening? 应用程序的配置方式是否有问题可以说明为什么会发生这种情况?

I should add that restarting the Node.js instance fixes the issue, it's just not something that would be tolerable in production. 我应该补充一点,重新启动Node.js实例可以解决这个问题,它不是生产中可以容忍的东西。

Thanks. 谢谢。

UPDATE : I ran Fiddler to see what was happening with HTTP/S traffic, and I can see that when it works initially, I'm getting a cookie set in the browser (I tried several) which is then passed back to the server on subsequent requests. 更新 :我运行Fiddler看看HTTP / S流量发生了什么,我可以看到,当它最初工作时,我在浏览器中设置了一个cookie(我尝试了几个)然后传回服务器后续请求。

When it doesn't work, the browser is not passing cookies to the server, and so Node is sending a Set-Cookie header that provides a new cookie each time. 当它不起作用时 ,浏览器不会将cookie传递给服务器,因此Node发送的Set-Cookie标头每次都会提供一个新的cookie。 So far I've had no luck determining the cause of this. 到目前为止,我没有运气确定原因。

I figured it out, although I don't love the answer. 我想通了,虽然我不喜欢这个答案。

tl;dr; TL;博士; - use maxAge instead of expires. - 使用maxAge而不是expires。


The issue was rooted in the expiration date set on each cookie (which is automatically set by Express). 该问题根植于每个cookie上设置的到期日期(由Express自动设置)。 I noticed that every cookie that was set had the same expiration date, which eventually ended up being in the past and hence instantly expiring. 我注意到,所设置的每个cookie都有相同的到期日期,最终结束于过去,因此即将到期。

The cause of that was here: 原因在于:

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

The new Date was being created only once, upon server start. 在服务器启动时,新日期仅创建一次。 That was causing the expiration date to be the same every time. 这导致到期日期每次都相同。 Based on code in the original post, I can't figure out why it doesn't work and yet every example I've found online uses the exact same code. 基于原始帖子中的代码,我无法弄清楚它为什么不起作用,但我在网上找到的每个例子都使用完全相同的代码。 I verified this by defining a function that created this Date, and checking that it only got called upon server start. 我通过定义创建此Date的函数并检查它是否仅在服务器启动时调用来验证这一点。

To fix this issue, I am defining maxAge instead of "expires". 要解决此问题,我正在定义maxAge而不是“expires”。 maxAge takes a number of milliseconds, rather than a date, and it appears to be setting the expiration date on all cookies correctly. maxAge需要几毫秒而不是一个日期,它似乎正在正确设置所有cookie的到期日期。

I would love to hear if anyone can explain why this is happening in the first place, since others seem to use it successfully. 我很想知道是否有人能够解释为什么会发生这种情况,因为其他人似乎成功地使用它。 Any thoughts? 有什么想法吗?

See my working code below 请参阅下面的工作代码

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

Set cookie name to value, where which may be a string or object converted to JSON. 将cookie名称设置为value,其中可以是转换为JSON的字符串或对象。 The path option defaults to "/". path选项默认为“/”。

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

The maxAge option is a convenience option for setting "expires" relative to the current time in milliseconds. maxAge选项是一个方便的选项,用于设置相对于当前时间的“到期”(以毫秒为单位)。 The following is equivalent to the previous example. 以下等同于前面的示例。

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

Also the Link 也是链接

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

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

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