feat: add refresh cookie reader

This commit is contained in:
2026-04-21 13:34:54 +08:00
parent adaf514a1a
commit 39eb7a513c
12 changed files with 653 additions and 11 deletions

View File

@@ -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` 的会话吊销。

View File

@@ -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` 迁移规则。

View File

@@ -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
交付: