# `/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](./MULTI_DEVICE_SESSION_IDENTITY_DESIGN_2026-04-21.md) 2. [SPACETIMEDB_REFRESH_SESSION_TABLE_DESIGN_2026-04-21.md](./SPACETIMEDB_REFRESH_SESSION_TABLE_DESIGN_2026-04-21.md) 3. [AUTH_REFRESH_ROTATION_DESIGN_2026-04-21.md](./AUTH_REFRESH_ROTATION_DESIGN_2026-04-21.md) 4. [AUTH_LOGOUT_CURRENT_SESSION_DESIGN_2026-04-21.md](./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 成功响应 ```json { "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. `clientRuntime`、`clientPlatform`、`deviceDisplayName` 是多端识别首版最小新增字段 3. 小程序来源额外暴露 `miniProgramAppId`、`miniProgramEnv` ### 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. 派生 `ipMasked` 与 `isCurrent` ## 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. 文档、任务清单与测试已同步更新