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

5.2 KiB
Raw Blame History

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
  2. 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 固定枚举为 LaxStrictNone
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 的会话吊销。