Session / 会话

WEB 请求中经常通过 session 来维持会话的,框架通过 think-session 和 Adapter 来支持 session 功能。

配置扩展和 Adapter

修改扩展配置文件 src/config/extend.js(多模块项目为 src/common/config/extend.js),添加下面的配置:

  1. const session = require('think-session');
  2. module.exports = [
  3. session
  4. ]

修改 Adapter 配置文件 src/config/adapter.js(多模块项目为 src/common/config/adapter.js),添加下面的配置:

  1. const fileSession = require('think-session-file');
  2. exports.session = {
  3. type: 'file',
  4. common: {
  5. cookie: {
  6. name: 'thinkjs',
  7. keys: ['signature key'],
  8. signed: true
  9. }
  10. },
  11. file: {
  12. handle: fileSession,
  13. sessionPath: path.join(think.ROOT_PATH, 'runtime/session')
  14. }
  15. }

支持的 session 类型列表见:https://github.com/thinkjs/think-awesome#session,其中 cookie 选项为 session 设置 cookie 时的配置项,会和 think.config('cookie') 值进行合并,name 字段值为 session 对应 cookie 的名字。

注入的方法

添加 think-session 扩展后,会注入 ctx.sessioncontroller.session 方法,其中 controller.session 是 ctx.session 方法的包装,会读取当前请求下对应的配置。

读取 session

  1. module.exports = class extends think.Controller {
  2. // 获取 session
  3. async indexAction() {
  4. const data = await this.session('name');
  5. }
  6. }

设置 session

  1. module.exports = class extends think.Controller {
  2. // 设置 session
  3. async indexAction() {
  4. await this.session('name', 'value');
  5. }
  6. }

删除 session

  1. module.exports = class extends think.Controller {
  2. // 删除整个 session
  3. async indexAction() {
  4. await this.session(null);
  5. }
  6. }

常见问题

一个请求下能操作不同类型的 session 么?

不能。session 数据是异步更新的,所以一个请求下只允许使用一种 session。

session 数据是怎么同步的?

当 session 数据改变后,并不会立即更新到 session 容器里(为了性能考虑),而是在请求结束时统一更新。

  1. this.ctx.res.once('finish', () => {
  2. // 在请求结束时将 session flush 到存储容器中
  3. });

session 对应 cookie 的值是不能手工设置的,而是框架自动生成,生成方式为 think.uuid。后续 Action 中可以通过 this.cookie('thinkjs')获取到该 cookie (thinkjs 为 session 对应 cookie 的字段名称)。

如何限制同一个帐号在不同的端登录?

有些情况下,只允许一个帐号在一个端下登录,如果换了一个端,需要把之前登录的端踢下线(默认情况下,同一个帐号可以在不同的端下同时登录的)。这时候可以借助一个服务保存用户唯一标识和 session cookie 值的对应关系,如果同一个用户,但 cookie 不一样,则不允许登录或者把之前的踢下线。如:

  1. // 当用户登录成功后
  2. const cookie = this.cookie('thinkjs');
  3. const uid = userInfo.id;
  4. await this.redis.set(`uid-${uid}`, cookie);
  5. // 请求时,判断 session cookie 值是否相同
  6. const userInfo = await this.session('userInfo');
  7. const cookie = this.cookie('thinkjs');
  8. const saveCookie = await this.redis.get(`uid-${userInfo.id}`);
  9. if(saveCookie && saveCookie !== cookie) {
  10. // 不是最近一台登录的设备
  11. }

原文: https://thinkjs.org/zh-cn/doc/3.0/session.html