Node.js Express Passport Cookie过期 [英] Node.js Express Passport Cookie Expiration

查看:117
本文介绍了Node.js Express Passport Cookie过期的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在我的应用程序中使用护照进行身份验证,我也使用Express。总结一下我的问题:我的登录功能在初期工作正常,但是在任何用户的会话超时后,用户可以登录。

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



我将尽可能地包括一个例子在我的设置中:

  // ------------- 
//设置Passport
// -------------
var userModel = require('./ models / user')(db);
passport.use(new LocalStrategy(
function(username,password,done){
var errorMessage ='不正确的用户名/密码组合';
userModel.GetUserByUsername(username,函数(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});
}

//更新登录日期
userModel.UpdateUserWithLogin(username,user.currentLoginTime,function(err){
/ /如果我们在这里有一个错误,我们应该可以只记录
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);
});
});

// -------------
//设置快捷并配置
// ---------- ---
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',merged.swig);
app.set('view engine','html');
swig.init ({
root:'。',
allowErrors:true,//允许错误被抛出并被express而不是被压制
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 .now()+ 3600000)} // 1小时
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
app.use(expressValidator);

app.use(expres s.static(path.join(__ dirname,'public')));

//动态助手
app.use(require('./ helpers / DynamicHelpers'));

app.use(app.router);
});

app.get('/ login',routes.login);
app.post('/ login',passport.authenticate('local',{failureRedirect:'/ login',
badRequestMessage:请输入用户名和密码,
failureFlash:true }),
函数(req,res){
var targetUrl = req.session.pageAfterLogin;
delete req.session.pageAfterLogin;
res.redirect(targetUrl ||' / account');
});

app.get('/ account',IsAuthenticated,routes.account.show);

而IsAuthenticated帮助函数:

 函数IsAuthenticated(req,res,next){
if(req.isAuthenticated())
{
next();
}
else
{
//保存所请求的页面,然后重定向
req.session.pageAfterLogin = req.url;
req.flash(error,你必须先登录!);
res.redirect('/ login');
}
}

我可以通过调试找到的是,成功后认证(并且Cookie过期后),我点击这个逻辑(从上面):

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

在哪里可以看到req正确设置会话,护照信息存储正确。然后,重定向发生,请求没有存储会话信息,并且具有全新的会话ID。我怀疑客户端上没有设置cookie,而且似乎是这样,这应该是缺乏一致的会话。



但是,我不能out 为什么没有设置新的cookie。应用程序配置是否出现问题,表明为什么会发生这种情况?



我应该添加重新启动Node.js实例来修复问题,只是不



谢谢。



更新:我运行Fiddler看看HTTP / S流量发生了什么,我可以看到,当它最初工作时,我在浏览器中收到了一个cookie(我尝试了几个),然后在随后的请求中传回给服务器。



工作时,浏览器不会将Cookie传递到服务器,因此Node正在发送Set-Cookie头,每次提供一个新的cookie。到目前为止,我没有运气确定这个原因。

解决方案

我想出来,虽然我不爱答案。



tl; dr; - 使用maxAge而不是expires。






该问题根植于每个Cookie设置的到期日期(自动设置通过Express)。我注意到每个设置的cookie都有相同的过期日期,最终终止于过去,因此会立即过期。



原因在于: / p>

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

在服务器启动时,新日期只被创建一次。这是导致到期日期相同的每一次。根据原始帖子中的代码,我无法弄清楚为什么它不起作用,但是我在网上找到的每个例子都使用完全相同的代码。我通过定义一个创建此Date的函数来验证这一点,并检查它仅在服务器启动时被调用。



为了解决这个问题,我定义了maxAge而不是过期。 maxAge需要几毫秒而不是日期,并且正好在所有的Cookie上正确设置过期日期。



我很乐意听到任何人都可以解释为什么这是发生在第一位,因为其他人似乎成功使用它。任何想法?



请看我下面的工作代码

  app.configure(function(){
app.set('port',process.env.PORT || 3000);
app.set('views',__dirname +'/ views') ;
app.engine('html',merged.swig);
app.set('view engine','html');
swig.init({
root :'。',
allowErrors:true,//允许错误被抛出并被catch而不是被压制
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')));

//动态助手
app.use(require('./ helpers / DynamicHelpers'));

app.use(app.router);
});


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.

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:

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):

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.

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?

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

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.

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.

解决方案

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

tl;dr; - use maxAge instead of 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.

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.

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

这篇关于Node.js Express Passport Cookie过期的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆