在Express.js中使用会话(Session)

37
我需要帮助理解Web应用程序会话的概念。我正在运行一个带有Express 3.0的Node.js服务器。
我的目标是:
- 为每个登录的用户创建一个会话。 - 存储该会话并将其用于验证该用户是否已经登录(防止两个设备同时使用相同的用户),以及限制访问某些页面(通过与会话ID匹配某些其他数据)。 我将使用MemoryStore保存会话(似乎最容易)。如果上述目标有意义,您能否提供如何实现这些目标的详细说明?

1
你应该看一下 Passport - mekwall
4
我已经尝试使用护照(passport)了,但无法正常工作。我认为使用 Express 中的默认会话(session)会更容易些。 - user1958595
1
你可能想阅读这篇文章:https://dev59.com/VGXWa4cB1Zd3GeqPMF7T。Session 只是一个带有唯一 ID 的数据库/内存条目。 - freakish
以下是有关Express框架中会话(Session)工作原理的相当详细的描述。https://dev59.com/r2035IYBdhLWcg3wQtyn#11585839 - Waylon Flinn
2个回答

41

Express在github仓库中有很好的示例。其中之一处理身份验证,并展示了如何将用户附加到req.session对象中。这是在app.post('/login')路由内完成的。

为了限制对某些页面的访问,在这些路由中添加一个简单的中间件即可。

function restrict(req, res, next) {
  if (req.session.user) {
    next();
  } else {
    req.session.error = 'Access denied!';
    res.redirect('/login');
  }
}

app.get('/restricted', restrict, function(req, res){
  res.send('Wahoo! restricted area, click to <a href="/logout">logout</a>');
});

正如Brandon所提到的,你不应该在生产环境中使用MemoryStore。 Redis是一个很好的替代品。 使用connect-redis访问数据库。示例配置如下:

var RedisStore = require('connect-redis')(express);

// add this to your app.configure
app.use(express.session({
  secret: "kqsdjfmlksdhfhzirzeoibrzecrbzuzefcuercazeafxzeokwdfzeijfxcerig",
  store: new RedisStore({ host: 'localhost', port: 3000, client: redis })
}));

你在哪里将两个session_id与cookie id进行比较? - aman verma
你能告诉我在使用Redis时,我是需要自己生成唯一的令牌还是Redis提供了这个功能? - aman verma

10

仅在没有创建多个实例(例如使用集群模块)的情况下,在express中使用MemoryStore。 如果您在不同机器之间进行负载平衡,则负载均衡器需要使用粘性/持久会话。

如果您满足这些要求,那么您只需要在登录时,在验证凭据后,设置一个会话变量以指示已登录,例如:

req.session.loggedIn = true;

如果您想检查用户是否已登录,请简单地检查该变量。

if (req.session.loggedIn) {
    // user is logged in.
}
else {
    // user is not logged in.
}

你提到需要防止单个用户同时拥有多个会话。为了实现这一点,你可能需要在数据库中存储一些内容来表示该用户已经登录。但我必须警告你,这可能存在风险,因为会话信息可能会很长时间保留。例如,如果一个用户登录后从未退出,或者关闭了浏览器导致会话信息永久丢失。

Express本身没有空闲会话过期的概念。我通过将所有的会话信息和最新访问时间戳存储在数据库中并定期清理会话数据来实现这一点。但是,这也意味着你需要更新已登录用户列表。


他可以覆盖上一个会话,以此禁用旧的会话并防止“过期会话”成为问题吗? - Neikos
不确定为什么他需要使用粘性端口而不是轮询?使用connect_redis的轮询将允许会话在网站的任何实例上工作。此外,作者声称它非常快(https://github.com/visionmedia/connect-redis),但您可能会失去一些性能,但您可以获得容错性。 - Eat at Joes
@Neikos:我需要实现这个机制,但是我很难解决它。你有什么建议吗?请在这里回答:https://dev59.com/P14b5IYBdhLWcg3wbRIf - vivekanon

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