节点。js Express Passport Cookie过期

时间:2021-11-21 12:31:11

I am using Passport for authentication in my app, and I am also using 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.

我在我的应用程序中使用护照进行身份验证,我也在使用Express。总结一下我的问题:我的登录功能最初运行良好,但是在任何用户的会话超时之后,没有用户能够登录。

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. Then, the redirect happens, the new request has no session information stored, and has an entirely new Session 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.

在这里,我可以看到“req”设置了正确的会话,并正确地存储了护照信息。然后,重定向发生了,新的请求没有存储的会话信息,并且有一个全新的会话ID。我怀疑客户端没有设置cookie,这似乎是事实,这应该解释缺乏一致会话的原因。

However, I cannot figure out why no new cookie is being set. Is there something wrong with how the app is configured that would indicate why this is happening?

但是,我不明白为什么没有设置新的cookie。应用程序的配置有问题吗?

I should add that restarting the Node.js instance fixes the issue, it's just not something that would be tolerable in production.

我应该添加重新启动节点。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. So far I've had no luck determining the cause of this.

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

2 个解决方案

#1


25  

I figured it out, although I don't love the answer.

我明白了,虽然我不喜欢这个答案。

tl;dr; - use maxAge instead of expires.

tl,博士;-使用maxAge而不是expires。


The issue was rooted in the expiration date set on each cookie (which is automatically set by 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上设置的过期日期(通过Express自动设置)。我注意到,每一个被设置的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.

在服务器启动时,只创建一次新日期。这导致每次过期日期都是相同的。根据最初文章中的代码,我不知道为什么它不能工作,但是我在网上找到的每个例子都使用相同的代码。我通过定义一个创建这个日期的函数来验证这一点,并检查它是否只在服务器启动时被调用。

To fix this issue, I am defining maxAge instead of "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而不是“expires”。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);
});

#2


-1  

Set cookie name to value, where which may be a string or object converted to JSON. The path option defaults to "/".

将cookie名称设置为value,其中可以是字符串或对象转换为JSON。路径选项默认为"/"。

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

cookie('记得我','1',{expires: new Date(日期.now() + 900000), httpOnly: true});

The maxAge option is a convenience option for setting "expires" relative to the current time in milliseconds. The following is equivalent to the previous example.

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

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

cookie('记得我','1',{maxAge: 900000, httpOnly: true})

Also the Link

同样的联系

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

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

#1


25  

I figured it out, although I don't love the answer.

我明白了,虽然我不喜欢这个答案。

tl;dr; - use maxAge instead of expires.

tl,博士;-使用maxAge而不是expires。


The issue was rooted in the expiration date set on each cookie (which is automatically set by 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上设置的过期日期(通过Express自动设置)。我注意到,每一个被设置的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.

在服务器启动时,只创建一次新日期。这导致每次过期日期都是相同的。根据最初文章中的代码,我不知道为什么它不能工作,但是我在网上找到的每个例子都使用相同的代码。我通过定义一个创建这个日期的函数来验证这一点,并检查它是否只在服务器启动时被调用。

To fix this issue, I am defining maxAge instead of "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而不是“expires”。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);
});

#2


-1  

Set cookie name to value, where which may be a string or object converted to JSON. The path option defaults to "/".

将cookie名称设置为value,其中可以是字符串或对象转换为JSON。路径选项默认为"/"。

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

cookie('记得我','1',{expires: new Date(日期.now() + 900000), httpOnly: true});

The maxAge option is a convenience option for setting "expires" relative to the current time in milliseconds. The following is equivalent to the previous example.

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

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

cookie('记得我','1',{maxAge: 900000, httpOnly: true})

Also the Link

同样的联系

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

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