3.0 KiB
3.0 KiB
Auth refresh session 持久化热修方案
日期:2026-04-24
1. 背景
当前 Rust 鉴权链路已经具备 refresh cookie 自动续签能力:access token 过期后,前端会调用 POST /api/auth/refresh,后端轮换 refresh token 并返回新的 access token。
但 module-auth 当前仍使用进程内 InMemoryAuthStore 保存账号与 refresh session。只要 server-rs 在 access token 生命周期内发生重启,浏览器侧 HttpOnly cookie 仍然存在,服务端却找不到对应账号与 session,最终表现为约 JWT_EXPIRES_IN 后需要重新登录。
2. 本次目标
本次先落一个低风险持久化闭环,解决“后端重启导致 2 小时后必须重新登录”的线上体验问题:
- 为当前
InMemoryAuthStore增加 UTF-8 JSON 快照文件。 - 在账号、手机号索引、微信身份、refresh session 发生变更后自动保存快照。
api-server启动时从配置路径恢复快照。- 保持现有
/api/auth/refresh、logout、sessions语义不变。
3. 非目标
本次不把完整认证域一次性迁入 SpacetimeDB 表,原因是 refresh session 独立持久化不足以解决问题:refresh 成功后还需要按 user_id 读取账号快照重新签发 access token,因此账号主数据也必须同源恢复。
SpacetimeDB 正式表接管仍按以下既有文档继续推进:
docs/technical/SPACETIMEDB_AUTH_USER_ACCOUNT_TABLE_DESIGN_2026-04-21.mddocs/technical/SPACETIMEDB_AUTH_IDENTITY_TABLE_DESIGN_2026-04-21.mddocs/technical/SPACETIMEDB_REFRESH_SESSION_TABLE_DESIGN_2026-04-21.md
4. 配置
新增环境变量:
| 变量 | 默认值 | 说明 |
|---|---|---|
GENARRATIVE_AUTH_STORE_PATH |
server-rs/.data/auth-store.json |
当前 Rust 鉴权快照文件路径。相对路径按进程工作目录解析。 |
5. 数据边界
快照文件保存当前 Rust 鉴权服务已经在内存中维护的最小真相:
next_user_idusers_by_usernamephone_to_user_idsessions_by_idsession_id_by_refresh_token_hashwechat_identity_by_provider_uiduser_id_by_provider_union_id
短信验证码和微信 OAuth state 不持久化,原因是它们是短生命周期挑战数据,重启后失效是可接受行为。
6. 安全约束
- refresh token 原文仍只存在浏览器 HttpOnly cookie,快照只保存
sha256(refresh_token)。 - 快照包含
password_hash、手机号映射和 refresh token hash,部署时必须放在服务端私有目录,不允许暴露到静态资源目录。 - 快照写入必须使用 UTF-8,并通过临时文件原子替换降低写坏风险。
7. 后续 SpacetimeDB 接管点
当 user_account、auth_identity、refresh_session 表及 reducer 全部落地后,替换策略如下:
- 保留
module-auth用例语义。 - 把当前快照仓储替换为 SpacetimeDB 仓储适配器。
- 启动时可提供一次性导入脚本,把 JSON 快照导入 SpacetimeDB 表。
- 导入完成后禁用
GENARRATIVE_AUTH_STORE_PATH快照写入。