Files
Genarrative/docs/technical/AUTH_LOGOUT_ALL_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

178 lines
4.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# `/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. 文档、任务清单与测试已同步更新