feat: add logout all flow

This commit is contained in:
2026-04-21 16:50:56 +08:00
parent 78dcad1222
commit c3c5f1acd7
7 changed files with 589 additions and 2 deletions

View File

@@ -0,0 +1,177 @@
# `/api/auth/logout-all` 全端登出落地设计
日期:`2026-04-21`
## 1. 文档目的
这份文档用于指导 `M2``实现全端登出` 的首版落地,冻结:
1. `POST /api/auth/logout-all` 的请求与响应 contract
2. 全部 refresh session 吊销与 `token_version` 递增的组合语义
3. Rust 首版在进程内鉴权真相中的最小实现边界
4.`/logout``/sessions/:sessionId/revoke` 的职责切分
## 2. 当前基线
当前 Node `/api/auth/logout-all` 已具备以下稳定语义:
1. 必须先通过 Bearer JWT 校验
2. 对当前用户执行 `token_version + 1`
3. 吊销该用户全部未吊销 refresh session
4. 响应成功时始终清理 refresh cookie
因此Node 的“退出全部设备”同样是两层组合动作:
1. 会话级:吊销同一账号全部 refresh session
2. 用户级:递增 `token_version`,让全部旧 access token 立即失效
Rust 首版必须保留这个语义。
## 3. 当前阶段范围
本阶段只落以下内容:
1. `module-auth` 增加按 `user_id` 吊销全部 refresh session 的能力
2. `api-server` 暴露 `POST /api/auth/logout-all`
3. 成功场景统一清理 refresh cookie
本阶段明确不包含:
1. `/api/auth/sessions/:sessionId/revoke`
2. 审计日志正式落表
3. SpacetimeDB reducer 真正写表
## 4. contract
### 4.1 请求
1. 方法:`POST`
2. 路径:`/api/auth/logout-all`
3. 请求体:空
4. 鉴权:
- Bearer JWT 必填
- refresh cookie 选填
### 4.2 成功响应
```json
{
"ok": true
}
```
同时响应头必须写回清理后的 refresh cookie。
### 4.3 失败响应
以下情况返回 `401 UNAUTHORIZED`
1. Bearer JWT 缺失或非法
2. JWT 对应用户不存在
## 5. 固定语义
### 5.1 动作顺序
`POST /api/auth/logout-all` 固定按以下顺序执行:
1. 从 Bearer JWT 解析当前用户
2. 批量吊销当前用户全部 refresh session
3. 对当前用户执行 `token_version + 1`
4. 返回 `ok: true`
5. 始终清理 refresh cookie
### 5.2 `token_version` 只递增一次
无论当前用户存在多少会话:
1. `logout-all` 只递增一次 `token_version`
2. 不为每条 session 单独递增版本号
### 5.3 缺少 refresh cookie 不影响成功
`logout-all` 是账号级动作,不依赖当前 refresh cookie 命中:
1. 即使当前设备没有 refresh cookie也要允许完成全端登出
2. 成功响应仍然统一清理 cookie
## 6. 与其他接口的职责切分
### 6.1 `/api/auth/logout`
负责:
1. 当前设备退出
2. 当前 refresh session 尽力吊销
3. `token_version` 递增一次
### 6.2 `/api/auth/logout-all`
负责:
1. 全部设备退出
2. 当前用户全部 refresh session 吊销
3. `token_version` 递增一次
### 6.3 `/api/auth/sessions/:sessionId/revoke`
后续负责:
1. 只吊销指定远端设备 refresh session
2. 不递增 `token_version`
## 7. crate 边界
### 7.1 `module-auth`
负责:
1.`user_id` 吊销全部 refresh session
2. 递增当前用户 `token_version`
3. 返回最新用户快照
### 7.2 `platform-auth`
负责:
1. 构造清理 cookie 的 `Set-Cookie`
### 7.3 `api-server`
负责:
1. Bearer JWT 读取与校验
2. 调用 `module-auth` 执行全端登出
3. 始终回写清理 cookie
## 8. 进程内实现策略
当前阶段 `module-auth` 继续使用进程内真相,新增以下最小能力:
1. `revoke_all_sessions_by_user_id`
2. `logout_all_sessions`
其中:
1. 批量吊销只改 `revoked_at`
2. 用户版本递增继续直接修改内存用户快照
## 9. 测试策略
至少覆盖:
1. 登录两次后调用 `/api/auth/logout-all` 返回 `ok: true`
2. `/logout-all` 成功后清理 refresh cookie
3. `/logout-all` 成功后旧 Bearer token 访问 `/api/auth/me` 返回 `401`
4. `/logout-all` 成功后旧 refresh cookie 调用 `/api/auth/refresh` 返回 `401`
5. 缺少 refresh cookie 时,只要 Bearer token 有效,`/logout-all` 仍返回 `ok: true`
## 10. 完成定义
满足以下条件时,本任务视为完成:
1. Rust 侧已提供 `POST /api/auth/logout-all`
2. 同一用户全部 refresh session 可被吊销
3. 用户 `token_version` 会在全端登出时递增
4. `/logout-all` 总会清理 refresh cookie
5. 文档、任务清单与测试已同步更新

View File

@@ -5,6 +5,7 @@
## 文档列表
- [AUTH_ME_QUERY_DESIGN_2026-04-21.md](./AUTH_ME_QUERY_DESIGN_2026-04-21.md)`/api/auth/me` 首版查询设计,冻结 Bearer JWT 衔接、`user + availableLoginMethods` 返回 contract以及用户不存在时的 `401` 语义。
- [AUTH_LOGOUT_ALL_DESIGN_2026-04-21.md](./AUTH_LOGOUT_ALL_DESIGN_2026-04-21.md)`/api/auth/logout-all` 全端登出设计,冻结全部 refresh session 吊销、`token_version` 递增、清 cookie 语义与 Rust 首版接口边界。
- [AUTH_SESSIONS_QUERY_DESIGN_2026-04-21.md](./AUTH_SESSIONS_QUERY_DESIGN_2026-04-21.md)`/api/auth/sessions` 会话列表设计,冻结当前设备识别、多端登录字段映射、`clientLabel` 兼容策略与 Rust 首版接口边界。
- [PASSWORD_ENTRY_FLOW_DESIGN_2026-04-21.md](./PASSWORD_ENTRY_FLOW_DESIGN_2026-04-21.md):密码登录与自动建号落地设计,冻结 `/api/auth/entry`、幂等兼容策略、模块边界以及与 JWT / refresh cookie 的衔接方式。
- [MULTI_DEVICE_SESSION_IDENTITY_DESIGN_2026-04-21.md](./MULTI_DEVICE_SESSION_IDENTITY_DESIGN_2026-04-21.md):多端登录会话身份模型设计,冻结浏览器、小程序、微信内 H5 的客户端身份字段、请求头约定与展示名派生规则。
@@ -20,6 +21,7 @@
- [SPACETIMEDB_AUTH_IDENTITY_TABLE_DESIGN_2026-04-21.md](./SPACETIMEDB_AUTH_IDENTITY_TABLE_DESIGN_2026-04-21.md)`M2` 第二张身份表 `auth_identity` 的 provider 范围、唯一约束、手机号/微信身份写入规则与迁移策略。
- [SPACETIMEDB_AUTH_USER_ACCOUNT_TABLE_DESIGN_2026-04-21.md](./SPACETIMEDB_AUTH_USER_ACCOUNT_TABLE_DESIGN_2026-04-21.md)`M2` 第一张身份主表 `user_account` 的职责边界、字段、唯一约束、状态迁移、旧 `users` 映射与落地约束。
- [SPACETIMEDB_AXUM_OSS_BACKEND_REWRITE_DESIGN_2026-04-20.md](./SPACETIMEDB_AXUM_OSS_BACKEND_REWRITE_DESIGN_2026-04-20.md):基于当前 Node 后端能力清单,设计用 `SpacetimeDB + Axum + 阿里云 OSS` 重写后端的目标架构、模块映射、数据分层、迁移顺序与验收标准。
- [AXUM_TO_SPACETIMEDB_ASSET_OBJECT_CONFIRM_CALL_DESIGN_2026-04-21.md](./AXUM_TO_SPACETIMEDB_ASSET_OBJECT_CONFIRM_CALL_DESIGN_2026-04-21.md):冻结 `POST /api/assets/objects/confirm` 从 Axum 通过 Rust SDK 调用 `SpacetimeDB procedure` 的最小落地方案,明确本地 server、数据库名、procedure/reducer 分工与 `spacetime-client` 边界。
- [REPO_NOISE_CLEANUP_BASELINE_2026-04-19.md](./REPO_NOISE_CLEANUP_BASELINE_2026-04-19.md):落实工程清理审计第一阶段后的仓库噪音清理范围、忽略规则闭合点与后续约束。
- [PROMPT_DIRECTORY_MANAGEMENT_2026-04-19.md](./PROMPT_DIRECTORY_MANAGEMENT_2026-04-19.md):后端提示词收口到 `server-node/src/prompts/` 的目录方案、兼容策略与后续新增规则。
- [CUSTOM_WORLD_DRAFT_GENERATION_FAILURE_ANALYSIS_AND_FIX_2026-04-20.md](./CUSTOM_WORLD_DRAFT_GENERATION_FAILURE_ANALYSIS_AND_FIX_2026-04-20.md):世界草稿生成失败后等待页误显示为“卡在编译草稿卡”的根因拆解、主链与增强链路边界,以及本次修复策略。