feat: add refresh cookie reader
This commit is contained in:
@@ -0,0 +1,173 @@
|
||||
# platform-auth refresh cookie 适配设计
|
||||
|
||||
日期:`2026-04-21`
|
||||
|
||||
## 1. 文档目的
|
||||
|
||||
这份文档用于指导 `M2` 中“实现 refresh cookie 读取”这条任务落地,目标是先把 refresh cookie 的读取边界、配置口径与 `api-server` 的最小接线固定下来。
|
||||
|
||||
本阶段只解决:
|
||||
|
||||
1. `platform-auth` 如何统一读取 refresh cookie。
|
||||
2. `api-server` 如何把读取结果挂到请求上下文。
|
||||
|
||||
本阶段不解决:
|
||||
|
||||
1. refresh token 轮换。
|
||||
2. refresh session 吊销。
|
||||
3. refresh cookie 写回浏览器。
|
||||
|
||||
## 2. 设计输入
|
||||
|
||||
本任务直接受以下文档约束:
|
||||
|
||||
1. [SPACETIMEDB_REFRESH_SESSION_TABLE_DESIGN_2026-04-21.md](./SPACETIMEDB_REFRESH_SESSION_TABLE_DESIGN_2026-04-21.md)
|
||||
2. [SPACETIMEDB_AXUM_OSS_BACKEND_REWRITE_DESIGN_2026-04-20.md](./SPACETIMEDB_AXUM_OSS_BACKEND_REWRITE_DESIGN_2026-04-20.md)
|
||||
|
||||
关键冻结点:
|
||||
|
||||
1. 浏览器 cookie 只存原始 refresh token。
|
||||
2. 服务端真相表只存 `sha256(refresh_token)`。
|
||||
3. cookie 名默认是 `genarrative_refresh_session`。
|
||||
4. cookie `Path` 默认是 `/api/auth`。
|
||||
5. 默认 `SameSite=Lax`。
|
||||
|
||||
## 3. crate 边界
|
||||
|
||||
### 3.1 `platform-auth`
|
||||
|
||||
负责:
|
||||
|
||||
1. 统一 refresh cookie 配置结构。
|
||||
2. 统一 cookie 名、Path、SameSite、Secure、TTL 的平台配置。
|
||||
3. 从 `Cookie` 请求头解析当前 refresh token。
|
||||
|
||||
不负责:
|
||||
|
||||
1. 直接操作 `Set-Cookie` 响应头。
|
||||
2. 决定请求是否应该被视为已登录。
|
||||
3. 访问 `refresh_session` 真相表。
|
||||
|
||||
### 3.2 `api-server`
|
||||
|
||||
负责:
|
||||
|
||||
1. 从环境变量读取 refresh cookie 配置。
|
||||
2. 在启动时构造唯一一份 `RefreshCookieConfig`。
|
||||
3. 在请求链中读取 refresh cookie 并挂到 request extensions。
|
||||
4. 为阶段验收提供最小内部调试入口。
|
||||
|
||||
不负责:
|
||||
|
||||
1. 重写一套独立 cookie 解析逻辑。
|
||||
2. 在这一步直接实现 `/api/auth/refresh`。
|
||||
|
||||
## 4. 配置口径
|
||||
|
||||
当前阶段 `api-server` 读取以下环境变量:
|
||||
|
||||
| 配置项 | 环境变量 | 默认值 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| cookie 名 | `AUTH_REFRESH_COOKIE_NAME` | `genarrative_refresh_session` | 读取 refresh cookie 时匹配的键名。 |
|
||||
| cookie path | `AUTH_REFRESH_COOKIE_PATH` | `/api/auth` | 当前阶段只用于冻结配置口径。 |
|
||||
| cookie secure | `AUTH_REFRESH_COOKIE_SECURE` | `false` | 当前阶段只读配置,不在读取路径参与判断。 |
|
||||
| cookie same-site | `AUTH_REFRESH_COOKIE_SAME_SITE` | `Lax` | 固定枚举为 `Lax`、`Strict`、`None`。 |
|
||||
| session TTL 天数 | `AUTH_REFRESH_SESSION_TTL_DAYS` | `30` | 当前阶段只读配置,不参与读取判断。 |
|
||||
|
||||
说明:
|
||||
|
||||
1. 这组变量直接对齐当前 Node 口径。
|
||||
2. 本阶段读取链路只真正依赖 `cookie_name`,其余配置主要用于冻结统一初始化边界。
|
||||
|
||||
## 5. Rust 结构设计
|
||||
|
||||
### 5.1 `RefreshCookieSameSite`
|
||||
|
||||
用途:
|
||||
|
||||
1. 避免不同 crate 手写 `Lax` / `Strict` / `None` 字符串。
|
||||
2. 在启动阶段尽早拒绝非法配置。
|
||||
|
||||
### 5.2 `RefreshCookieConfig`
|
||||
|
||||
字段:
|
||||
|
||||
1. `cookie_name`
|
||||
2. `cookie_path`
|
||||
3. `cookie_secure`
|
||||
4. `cookie_same_site`
|
||||
5. `refresh_session_ttl_days`
|
||||
|
||||
约束:
|
||||
|
||||
1. `cookie_name` 不能为空。
|
||||
2. `cookie_path` 不能为空。
|
||||
3. `refresh_session_ttl_days` 必须大于 `0`。
|
||||
|
||||
## 6. 读取规则
|
||||
|
||||
`read_refresh_session_token(cookie_header, config)` 固定按以下规则工作:
|
||||
|
||||
1. 若 `Cookie` 头为空,返回 `None`。
|
||||
2. 按 `;` 分割各 cookie 项。
|
||||
3. 只匹配与 `config.cookie_name` 完全相等的键名。
|
||||
4. 若匹配项值为空,返回 `None`。
|
||||
5. 对匹配值执行 URL decode。
|
||||
6. decode 成功则返回原始 refresh token,失败则返回 `None`。
|
||||
|
||||
说明:
|
||||
|
||||
1. 当前阶段读取逻辑只做“解析”,不做权限判断。
|
||||
2. 请求是否能继续 refresh,要在后续应用层结合 `refresh_session` 真相表判断。
|
||||
|
||||
## 7. api-server 最小接线
|
||||
|
||||
本阶段 `api-server` 只做三件事:
|
||||
|
||||
1. `AppConfig` 增加 refresh cookie 配置。
|
||||
2. `AppState` 启动时构造 `RefreshCookieConfig`。
|
||||
3. `attach_refresh_session_token` 中间件从请求头读取 cookie,并把结果以 `RefreshSessionToken` 写入 request extensions。
|
||||
|
||||
阶段验收入口:
|
||||
|
||||
1. `/_internal/auth/refresh-cookie`
|
||||
|
||||
该入口仅返回:
|
||||
|
||||
1. `cookieName`
|
||||
2. `present`
|
||||
3. `tokenLength`
|
||||
|
||||
说明:
|
||||
|
||||
1. 当前不回显原始 refresh token,避免把敏感值直接暴露到响应体中。
|
||||
2. `tokenLength` 只用于阶段测试与调试,不是最终对外 contract。
|
||||
|
||||
## 8. 测试策略
|
||||
|
||||
当前阶段至少覆盖:
|
||||
|
||||
1. 纯函数能正确提取目标 cookie。
|
||||
2. URL 编码的 cookie 值能正确解码。
|
||||
3. 缺少目标 cookie 时返回空。
|
||||
4. `api-server` 在无 cookie 时能返回 `present = false`。
|
||||
5. `api-server` 在有 cookie 时能返回 `present = true`。
|
||||
|
||||
## 9. 完成定义
|
||||
|
||||
满足以下条件时,本任务视为完成:
|
||||
|
||||
1. `platform-auth` 中存在真实可编译的 refresh cookie 配置与读取逻辑。
|
||||
2. `api-server` 已接入统一 refresh cookie 配置。
|
||||
3. 请求链已能读取 cookie 并挂到 extensions。
|
||||
4. 编译与测试通过。
|
||||
5. 任务清单已同步更新。
|
||||
|
||||
## 10. 后续衔接
|
||||
|
||||
这条任务完成后,下一步继续衔接:
|
||||
|
||||
1. refresh token 哈希与 `refresh_session` 表查询。
|
||||
2. refresh token 轮换。
|
||||
3. `/api/auth/refresh` 正式接口。
|
||||
4. `/api/auth/logout`、`/api/auth/logout-all` 的会话吊销。
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
## 文档列表
|
||||
|
||||
- [PLATFORM_AUTH_REFRESH_COOKIE_ADAPTER_DESIGN_2026-04-21.md](./PLATFORM_AUTH_REFRESH_COOKIE_ADAPTER_DESIGN_2026-04-21.md):`platform-auth` refresh cookie 适配设计,冻结 cookie 配置结构、读取规则与 `api-server` 最小读取链路。
|
||||
- [PLATFORM_AUTH_JWT_ADAPTER_DESIGN_2026-04-21.md](./PLATFORM_AUTH_JWT_ADAPTER_DESIGN_2026-04-21.md):`platform-auth` 首版 JWT 适配设计,冻结 `JwtConfig`、claims 结构、`HS256` 签发/校验、`api-server` Bearer 中间件与内部验收路由边界。
|
||||
- [OIDC_JWT_CLAIMS_DESIGN_2026-04-21.md](./OIDC_JWT_CLAIMS_DESIGN_2026-04-21.md):面向 Axum、`platform-auth` 与 `SpacetimeDB` 身份透传的 OIDC 风格 JWT claims 设计,冻结 `iss/sub/sid/provider/roles` 等关键字段。
|
||||
- [RUST_SHARED_LOGGING_CRATE_DESIGN_2026-04-21.md](./RUST_SHARED_LOGGING_CRATE_DESIGN_2026-04-21.md):Rust 工作区统一日志模块 `shared-logging` 的职责边界、API、输出风格与 `api-server` 迁移规则。
|
||||
|
||||
@@ -733,6 +733,11 @@ workflow-cache/{workflow_type}/{workflow_id}.json
|
||||
5. Axum -> SpacetimeDB 基础 client
|
||||
6. OIDC-compatible JWT 签发
|
||||
|
||||
阶段执行补充:
|
||||
|
||||
1. 微信登录链路在当前阶段暂缓,不进入连续执行顺序。
|
||||
2. 当前优先顺序固定为:JWT / refresh cookie / 密码登录 / 手机验证码登录。
|
||||
|
||||
## Phase 2:迁移 runtime snapshot / settings / profile
|
||||
|
||||
交付:
|
||||
|
||||
Reference in New Issue
Block a user