只能登录一个用户

持久化session,保存每一个登录用户的session。解决方式是使用 redis , express 框架配合 redis 相关的库可以非常方便地存储用户的session,如下配置 express-session 即可实现自动化地实现保存和删除session。

  1. const session = require('express-session')
  2. const redis = require('redis')
  3. const RedisStore = require('connect-redis')(session)
  4. let redisClient = redis.createClient()
  5. // 开放 redist 实例到全局,可以封装后 export 导出
  6. global.redisClient = redisClient
  7. app.use(
  8. session({
  9. name: 'blog_cookie',
  10. secret: 'secret key',
  11. resave: false,
  12. saveUninitialized: false,
  13. cookie: {
  14. httpOnly: true,
  15. maxAge: 24 * 60 * 60 * 1000,
  16. },
  17. store: new RedisStore({ client: redisClient }),
  18. })
  19. )

使用connect-redis前是想通过官方的express-session使用介绍中找到多用户登录的方法。之前的情况是想通过一个全局变量来保存每次下发的session,可是发现session集成到express后只能通过请求参数来获取用户访问时携带过来的cookie信息,尽管通过查询获知配置参数store可以告知session保存方式,可是这东西如果用数组或者set/map去保存,看起来似乎有点不可控,要是服务器挂了,那么所有用户的session就都没了。

于是在看到了官方这个文章最下面Seesion store Implementation的介绍推荐使用connect-redis时,就跟随官方推荐使用了。根据后面的了解,redis的好处是数据库运行在内存中,对于session这种小量存储,且I/O密集的数据利用内存速度优势可以提升访问速度。

此时通过RedisStore即可实现session的自动化存储了,来了一个用户,存到数据库中,用户退出了,自动从数据库中删除session对应的key:value

总结:解决思路是:session —> 多个session —> session持久化

多端不同用户登录,后登录的用户会影响到之前用户的主页信息展示

看起来已经完成多用户登录功能了,每个用户信息都实现了持久化存储,可是又由于此次是一个ssr项目(Express+art-template),用户在界面上展示的信息通过一个全局对象req.app.locals来保存,每次新的用户登录就会造成req.app.locals.user数据的更新,从而使博客主页的用户名被固定为最后登录系统的用户名。

解决办法:

  • 用户登录时将用户的信息跟随session一起保存到redis数据库中;
  • 根据浏览器访问服务器时会随之携带cookie信息,通过req.sessionID(sessionID是express-session生成的唯一id,这个值还可以通过req.session.id获取)对比数据库中的sessionID,取出在数据库中对应sessionID的user信息,重新赋值到req.app.locals.user中。

这样就可以保证每个用户来的时候服务器都提供正确的信息。

思路:

服务器不管来的人是谁(就像景区售票员,它只管卖票发票给客户,客户通过这个票据可以在规定时间范围内自由出入景区),只要你携带cookie,那么我就验证你的身份(通过对比数据库内的信息)。没有携带,只要可以合法登录,那就给浏览器发一个cookie。

项目中就是只要在页面内涉及使用req.app.locals.user的,那么就一定要验证cookie,并重新设置req.app.locals.user的值以保证服务器向用户提供服务时是唯一的。

最后,用了redis还是要稍微熟悉一下redis的,一开始完全不知道如何知道session是以什么样的方式保存到数据库中的,后来通过网络查询,知道在控制台中使用keys *命令可以获取所有的key,然后看到了sess:xxxxxx字样的key,再通过get 'sess:xxxxxx'看到了保存的session值。一步步尝试获取到了数据库中的session,然后在代码中通过redis的get函数获取值与req.sessionID做对比。