Files
Genarrative/docs/technical/AUTH_SESSIONS_QUERY_DESIGN_2026-04-21.md
kdletters cbc27bad4a
Some checks failed
CI / verify (push) Has been cancelled
init with react+axum+spacetimedb
2026-04-26 18:06:23 +08:00

5.4 KiB
Raw Blame History

/api/auth/sessions 会话列表与多端标识查询设计

日期:2026-04-21

1. 文档目的

这份文档用于指导 M2兼容 /api/auth/sessions 的首版落地,冻结:

  1. GET /api/auth/sessions 的请求与响应 contract
  2. 当前设备识别方式与 isCurrent 语义
  3. 多端登录识别字段如何从 refresh_session 派生到 DTO
  4. Rust 首版在 Axum + 进程内 module-auth 下的最小实现边界

2. 当前基线

当前 Node /api/auth/sessions 已具备以下稳定行为:

  1. 依赖 Bearer JWT 确认用户身份
  2. 从 refresh cookie 识别当前设备
  3. 返回当前账号全部未吊销活跃会话
  4. 每条记录给出端侧标签、最近活跃时间、到期时间、IP 脱敏信息与是否当前设备

当前问题是:

  1. 旧实现只能粗略给出“网页端浏览器 / 移动端浏览器”
  2. 无法稳定区分同设备不同浏览器
  3. 无法区分微信内 H5 与微信小程序、小程序平台来源

因此本次 /api/auth/sessions 首版落地必须直接承接多端会话身份模型。

3. 设计输入

本任务直接受以下文档约束:

  1. MULTI_DEVICE_SESSION_IDENTITY_DESIGN_2026-04-21.md
  2. SPACETIMEDB_REFRESH_SESSION_TABLE_DESIGN_2026-04-21.md
  3. AUTH_REFRESH_ROTATION_DESIGN_2026-04-21.md
  4. AUTH_LOGOUT_CURRENT_SESSION_DESIGN_2026-04-21.md

4. 首版落地范围

本阶段只落以下内容:

  1. module-auth 提供按 user_id 读取活跃 refresh session 列表的能力
  2. api-server 暴露 GET /api/auth/sessions
  3. 登录创建 session 时落库结构化客户端身份字段
  4. 会话列表返回多端识别所需字段,并兼容旧 clientLabel

本阶段明确不包含:

  1. /api/auth/sessions/:sessionId/revoke
  2. 前端完整消费全部新增字段
  3. SpacetimeDB reducer / view 正式读表

5. 请求与响应 contract

5.1 请求

  1. 方法:GET
  2. 路径:/api/auth/sessions
  3. 请求体:空
  4. 鉴权:
    • Bearer JWT 必填
    • refresh cookie 选填但建议携带,用于判断 isCurrent

5.2 成功响应

{
  "sessions": [
    {
      "sessionId": "usess_xxx",
      "clientType": "web_browser",
      "clientRuntime": "chrome",
      "clientPlatform": "windows",
      "clientLabel": "Windows / Chrome",
      "deviceDisplayName": "Windows / Chrome",
      "miniProgramAppId": null,
      "miniProgramEnv": null,
      "userAgent": "Mozilla/5.0 ...",
      "ipMasked": "203.0.*.*",
      "isCurrent": true,
      "createdAt": "2026-04-21T10:00:00Z",
      "lastSeenAt": "2026-04-21T10:05:00Z",
      "expiresAt": "2026-05-21T10:00:00Z"
    }
  ]
}

字段说明:

  1. clientLabel 当前阶段继续兼容旧前端字段,值固定与 deviceDisplayName 保持一致
  2. clientRuntimeclientPlatformdeviceDisplayName 是多端识别首版最小新增字段
  3. 小程序来源额外暴露 miniProgramAppIdminiProgramEnv

5.3 失败响应

以下情况返回 401 UNAUTHORIZED

  1. Bearer JWT 缺失或非法
  2. Bearer JWT 对应用户不存在

仓储读取失败返回 500 INTERNAL_SERVER_ERROR

6. 当前设备识别规则

isCurrent 固定按以下规则判断:

  1. 从 refresh cookie 读取当前原始 refresh token
  2. 在 Axum 侧计算 sha256(refresh_token)
  3. 与会话列表中的 refresh_token_hash 比较
  4. 命中则 isCurrent = true

说明:

  1. 如果请求没有携带 refresh cookie本接口仍可返回会话列表
  2. 此时全部会话的 isCurrent 都为 false

7. 多端标识派生规则

7.1 后端入库字段

登录创建会话时Axum 必须先解析并写入:

  1. client_type
  2. client_runtime
  3. client_platform
  4. client_instance_id
  5. device_fingerprint
  6. device_display_name
  7. mini_program_app_id
  8. mini_program_env
  9. user_agent
  10. ip

7.2 DTO 派生规则

会话列表返回时:

  1. clientType = client_type
  2. clientRuntime = client_runtime
  3. clientPlatform = client_platform
  4. deviceDisplayName = device_display_name
  5. clientLabel = device_display_name
  6. miniProgramAppId = mini_program_app_id
  7. miniProgramEnv = mini_program_env

8. crate 边界

8.1 module-auth

负责:

  1. 保存 refresh session 客户端身份快照
  2. user_id 返回活跃会话列表
  3. 保持 refresh 轮换后 session_id 稳定、客户端身份字段不漂移

8.2 api-server

负责:

  1. 读取 Bearer JWT 与 refresh cookie
  2. 把活跃会话映射成旧接口兼容 DTO
  3. 派生 ipMaskedisCurrent

9. 测试策略

至少覆盖:

  1. 同一账号在同平台不同浏览器登录后,会话列表能返回两条不同运行时记录
  2. 微信内 H5 登录后,会话列表返回 wechat_h5 + wechat_embedded_browser
  3. 显式小程序头优先于 User-Agent 判断
  4. 请求携带当前 refresh cookie 时,只有当前会话 isCurrent = true

10. 完成定义

满足以下条件时,本任务视为完成:

  1. Rust 侧已提供 GET /api/auth/sessions
  2. 会话列表可区分普通浏览器、微信内 H5、小程序来源
  3. 同设备不同浏览器可在会话列表中清晰区分
  4. clientLabel 与新增多端字段都已稳定返回
  5. 文档、任务清单与测试已同步更新