持久化认证状态到 SpacetimeDB 正式表

This commit is contained in:
2026-04-24 16:09:20 +08:00
parent 04288d4a40
commit 4e1c0462a4
29 changed files with 2271 additions and 7341 deletions

View File

@@ -0,0 +1,52 @@
# Auth SpacetimeDB 正式表恢复 Stage 3
## 1. 阶段目标
本阶段把认证持久化从“只依赖整包快照恢复”推进到“正式认证表优先恢复”。
落地口径:
- `user_account``auth_identity``refresh_session` 作为 SpacetimeDB 中的正式认证持久化表。
- API 启动时优先从正式表导出兼容 `module-auth` 的认证快照,再恢复到内存认证服务。
- 运行期认证变更仍先复用现有 `module-auth` 逻辑生成一致快照,随后同步快照并导入正式表,保证正式表与快照一致。
- 本阶段不重写登录、刷新、登出内部业务规则,避免在 JWT、refresh rotation、微信绑定合并等复杂语义中引入行为漂移。
## 2. 非目标
- 不在本阶段把 `PasswordEntryService``PhoneAuthService``RefreshSessionService` 改造成直接调用 SpacetimeDB reducer。
- 不在前端增加认证规则说明文案。
- 不删除 Stage 1 快照表;快照表继续作为导入载体与回滚兜底。
## 3. 运行流程
### 3.1 启动恢复
1. API 调用 `export_auth_store_snapshot_from_tables`
2. 若正式表已有用户、身份或会话数据,则返回兼容 `module-auth` 的 JSON 快照。
3. API 用 `InMemoryAuthStore::from_snapshot_json` 恢复认证服务。
4. 若正式表为空或调用失败,则回退到 Stage 1 的 `auth_store_snapshot`
5. 若 Stage 1 也不可用,则回退本地 JSON 热修复文件。
### 3.2 运行期同步
1. 登录、刷新、登出等路径继续调用当前内存认证服务。
2. 每次认证状态变更后调用 `upsert_auth_store_snapshot`
3. 快照写入成功后调用 `import_auth_store_snapshot`,覆盖导入正式表。
4. 导入失败时返回错误,避免用户误以为状态已经持久化。
## 4. 数据重建规则
- `users_by_username``user_account.username` 作为 key 重建。
- `phone_to_user_id` 由 provider 为 `phone``auth_identity` 重建。
- `wechat_identity_by_provider_uid` 由 provider 为 `wechat``auth_identity` 重建。
- `user_id_by_provider_union_id` 由微信身份中非空 `provider_union_id` 重建。
- `sessions_by_id``refresh_session.session_id` 重建。
- `session_id_by_refresh_token_hash``refresh_session.refresh_token_hash` 重建。
- `next_user_id` 取现有 `user_id``user_数字` 的最大值加一,若不存在则为 1。
## 5. 完成定义
- SpacetimeDB 模块能 wasm 编译。
- Rust bindings 已重新生成并包含正式表导出 procedure。
- `spacetime-client` 暴露正式表导出 facade。
- `api-server` 启动恢复优先正式表,认证变更同步后导入正式表。
- `module-auth` 测试保持通过。

View File

@@ -0,0 +1,97 @@
# Auth SpacetimeDB 拆表 Stage 2
日期:`2026-04-24`
## 1. 阶段目标
Stage 1 已把 Rust 鉴权快照同步到 SpacetimeDB 的 `auth_store_snapshot` 表。本阶段继续把该快照导入正式认证表,建立后续运行时细粒度读写的表结构基础。
本阶段落地范围:
1. 新增 `user_account` 表。
2. 新增 `auth_identity` 表。
3. 新增 `refresh_session` 表。
4. 新增 `import_auth_store_snapshot` procedure把当前 `auth_store_snapshot.snapshot_json` 拆入三张表。
5. 保留 Stage 1 快照表作为导入来源与回滚备份。
## 2. 非目标
本阶段不立即把 `api-server` 的登录、refresh、logout 写入切换到细粒度 reducer。原因是要避免同时改动认证业务语义、导入逻辑和运行时写路径。
运行时切换放到 Stage 3
1. `POST /api/auth/refresh` 改写 `refresh_session` 表。
2. 登录成功写 `user_account/auth_identity/refresh_session`
3. `logout/logout-all/revoke-session` 改写细粒度表。
4. `auth_store_snapshot` 退化为迁移备份。
## 3. 表设计落地口径
### 3.1 `user_account`
字段先覆盖当前 `module-auth` 快照可提供的账号主数据:
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `user_id` | `String` | 主键。 |
| `public_user_code` | `String` | 公开叙世号。 |
| `username` | `String` | 当前账号用户名。 |
| `display_name` | `String` | 展示名。 |
| `phone_number_masked` | `Option<String>` | 脱敏手机号。 |
| `phone_number_e164` | `Option<String>` | 内部手机号索引。 |
| `login_method` | `String` | `password/phone/wechat`。 |
| `binding_status` | `String` | `active/pending_bind_phone`。 |
| `wechat_bound` | `bool` | 是否绑定微信身份。 |
| `password_hash` | `String` | 密码哈希。 |
| `password_login_enabled` | `bool` | 是否允许密码登录。 |
| `token_version` | `u64` | access token 统一失效版本。 |
### 3.2 `auth_identity`
当前只导入已有快照中的微信身份与手机号身份:
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `identity_id` | `String` | 主键。 |
| `user_id` | `String` | 归属账号。 |
| `provider` | `String` | `phone/wechat`。 |
| `provider_uid` | `String` | provider 主体键。 |
| `provider_union_id` | `Option<String>` | 微信 unionid。 |
| `phone_e164` | `Option<String>` | 手机号身份。 |
| `display_name` | `Option<String>` | provider 显示名。 |
| `avatar_url` | `Option<String>` | provider 头像。 |
### 3.3 `refresh_session`
字段对齐现有 refresh session 记录:
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `session_id` | `String` | 主键。 |
| `user_id` | `String` | 归属账号。 |
| `refresh_token_hash` | `String` | 当前 refresh token hash。 |
| `issued_by_provider` | `String` | 创建来源。 |
| `client_info_json` | `String` | 当前客户端身份 JSON。 |
| `expires_at` | `String` | RFC3339。 |
| `revoked_at` | `Option<String>` | RFC3339。 |
| `created_at` | `String` | RFC3339。 |
| `updated_at` | `String` | RFC3339。 |
| `last_seen_at` | `String` | RFC3339。 |
## 4. 导入语义
`import_auth_store_snapshot` 固定行为:
1. 读取 `auth_store_snapshot/default`
2. JSON 解析失败返回 `ok=false` 和中文错误。
3. 导入前清空三张正式 auth 表,避免重复导入产生脏数据。
4. 按快照内容重建账号、身份、refresh session。
5. 返回导入计数,便于本地验证。
## 5. 完成定义
1. `spacetime-module` wasm check 通过。
2. Rust bindings 已刷新。
3. `spacetime-client` 暴露导入 procedure facade。
4. `api-server/spacetime-client/module-auth` 定向检查通过。