每次请求都更改Express会话

4
我有一个登录功能。
app.post('/doLogin', function(req,res){
        db.users.findOne({username: req.body.username}, function(err, user) {
            if( err ) {
                console.log("Login fail");
            } 
            else if (user != null) {
                if (req.body.password == user.password) {
                    req.session.user_role = "user";
                    req.session.save();
            } else {
                req.session.user_role = "null";
                console.log("Wrong login");
            }
        }
        res.send({redirect: "/"});
    });

});

该函数用于将一个变量保存到会话中 req.session.user_role = "user"; 但是当新的请求检查用户是否已登录时

app.get('/', function(req,res){
    redis.get('sess:' + req.session.id, function(err, result){
        console.log("Get session: " + util.inspect(JSON.parse(result),{ showHidden: true, depth: null }));
    });
    if ((req.session.user_role == "user")) {
          console.log("Logged in");
    } else {
        console.log("Logged out");
    }
});

每次返回的结果都是“已注销”,因为会话被更改了。我使用Redis存储会话,我认为是Redis的问题,因为当我停止使用Redis时,一切正常。

5个回答

19

Express-session使用cookie从客户端设置或获取会话ID,如文档中所述。

请注意,建议使用secure:true选项。但是,它需要启用HTTPS的网站,即仅在安全cookie上需要HTTPS。如果设置了secure,并且您通过HTTP访问站点,则不会设置cookie。

请记住以下几点:

  • 如果您没有在HTTPS连接上托管,cookie secure标志应该设置为false。

  • 如果您使用的代理托管在HTTPS上,则应该将信任代理设置为1。参考文档


以下选项可解决每个请求重置会话ID的问题

cookie: { secure: false }
例如:
app.use(session({
  // your settings
  cookie: { secure: false }
}))


1
谢谢,你帮我节省了很多时间。 - Daniel Khoroshko
文档还指出,cookie 的默认值为{ path: '/', httpOnly: true, secure: false, maxAge: null }。这个点上文档是错误的还是我漏掉了什么? - christophrus

3

如果可以的话,最好的做法是让Express自己处理它。

https://flaviocopes.com/express-sessions/(会话教程已更新,但链接不应视为答案)

有一个链接可以向您展示如何在Express中设置redis以进行会话。当处理会话时,您甚至不必自己查询redis,这是node中间件的工作。


我的新手气又来了。你的会话中间件是如何设置的?请发布一下。 - Chris
1
非常感谢,我设置了cookie: {secure: false},现在没问题了。但是我真的想知道如果我想设置{secure: true}的策略是什么。 - BlueS
关于 {secure: true} 的文档可以说是非常简略,但如果您的应用程序在反向代理后面,则可能与信任反向代理有关。 "可能" 是关键词。 - Chris
这个问题已经解决并且相当古老了,但它今天在我的多次搜索中出现,所以我将为那些处于同样情况下的人添加此信息:在Windows上,目前没有可用的Redis安装能够与express-session正常工作。我发现最简单的解决方法是启用Windows Subsystem for Linux,在命令提示符中安装Ubuntu,然后安装Redis,并从子系统进行主机设置。 - Jacob Runge

1

也许你的代码中存在一些异步错误。每当你有一个异步操作(比如回调函数),你都应该确保在回调函数执行后再执行其他代码,因此你可以将代码放入回调函数中。就像这样:

db.users.findOne({username: req.body.username}, function(err, user) {
  if( err ) {
    console.log("Login fail");
  } 
  else if (user != null) {
    if (req.body.password == user.password) {
      req.session.user_role = "user";
      req.session.save();
      res.send({redirect: "/"});
    } else {
      req.session.user_role = "null";
      console.log("Wrong login");
      res.send({redirect: "/"});
    }
  }
});

app.get 应该长这样:

app.get('/', function(req,res){
  redis.get('sess:' + req.session.id, function(err, result){
    console.log("Get session: " + util.inspect(JSON.parse(result),{ showHidden: true, depth: null }));
    if ((req.session.user_role == "user")) {
      console.log("Logged in");
    } else {
      console.log("Logged out");
    }
  });
});

1
如果设置了{secure:true},并且您通过HTTP访问您的网站,那么cookie将不会被设置。因此,每个请求都将创建一个新的会话。

0

到目前为止,所有的答案都有帮助,但并没有直接解决使用secure:true的问题。

为了使用secure:true,您必须支持https以获取安全cookie。此外,您必须使用withCredentials进行跨站点访问控制。withCrendentials:true对同一站点请求没有影响。

https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials

大多数库都支持在其配置中使用此参数,例如Angular和Dropzone。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接