feat: add platform auth jwt adapter
This commit is contained in:
217
docs/technical/PLATFORM_AUTH_JWT_ADAPTER_DESIGN_2026-04-21.md
Normal file
217
docs/technical/PLATFORM_AUTH_JWT_ADAPTER_DESIGN_2026-04-21.md
Normal file
@@ -0,0 +1,217 @@
|
||||
# platform-auth JWT 适配设计
|
||||
|
||||
日期:`2026-04-21`
|
||||
|
||||
## 1. 文档目的
|
||||
|
||||
这份文档用于指导 `platform-auth` 首个真实能力落地,目标是完成:
|
||||
|
||||
1. `platform-auth` crate 的 JWT claims 结构。
|
||||
2. access token 的签发与校验适配。
|
||||
3. `api-server` 的最小 Bearer JWT 校验入口。
|
||||
|
||||
这一步只解决“Axum 自身能稳定签发并校验 JWT”的基础问题,不提前把 refresh cookie、短信和微信 OAuth 一起耦合进来。
|
||||
|
||||
## 2. 当前落地范围
|
||||
|
||||
本阶段只包含以下实现:
|
||||
|
||||
1. `JwtConfig`
|
||||
2. `AccessTokenClaimsInput`
|
||||
3. `AccessTokenClaims`
|
||||
4. `sign_access_token(...)`
|
||||
5. `verify_access_token(...)`
|
||||
6. `api-server` 的 Bearer 鉴权中间件
|
||||
7. `/_internal/auth/claims` 内部调试路由
|
||||
|
||||
本阶段明确不包含:
|
||||
|
||||
1. refresh cookie 的生成、解析、轮换和吊销。
|
||||
2. 从 `module-auth` / `SpacetimeDB` 真相表读取 `token_version` 并做在线比对。
|
||||
3. 短信 provider 与微信 OAuth 平台适配。
|
||||
4. SpacetimeDB 模块对 Axum 签发 JWT 的消费代码。
|
||||
|
||||
## 3. 设计输入
|
||||
|
||||
本实现直接受以下文档约束:
|
||||
|
||||
1. [OIDC_JWT_CLAIMS_DESIGN_2026-04-21.md](./OIDC_JWT_CLAIMS_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. `iss/sub/sid/provider/roles/ver/phone_verified/binding_status` 是当前 access token 的固定字段。
|
||||
2. `sub` 是稳定 `user_id`。
|
||||
3. `sid` 是会话 ID,不是单次 token ID。
|
||||
4. `roles` 当前至少包含 `user`。
|
||||
5. 不允许把手机号、openid、风控状态、refresh token hash 放进 JWT。
|
||||
|
||||
## 4. crate 边界
|
||||
|
||||
### 4.1 `platform-auth`
|
||||
|
||||
负责:
|
||||
|
||||
1. 组织 JWT 结构。
|
||||
2. 执行签名与验签。
|
||||
3. 执行基础 claims 完整性校验。
|
||||
|
||||
不负责:
|
||||
|
||||
1. 用户是否存在。
|
||||
2. `token_version` 是否仍是数据库最新值。
|
||||
3. refresh session 是否已被吊销。
|
||||
4. provider 之外的业务规则判断。
|
||||
|
||||
### 4.2 `api-server`
|
||||
|
||||
负责:
|
||||
|
||||
1. 从 `Authorization` 头提取 Bearer token。
|
||||
2. 调用 `platform-auth` 校验。
|
||||
3. 把已校验 claims 写入请求上下文。
|
||||
4. 在本阶段提供最小内部验收入口 `/_internal/auth/claims`。
|
||||
|
||||
不负责:
|
||||
|
||||
1. 自己再实现一套 JWT 编解码逻辑。
|
||||
2. 把 claims 结构拆散成多个重复 helper。
|
||||
|
||||
## 5. 配置口径
|
||||
|
||||
当前阶段 `api-server` 读取并传入 `platform-auth` 的配置如下:
|
||||
|
||||
| 配置项 | 环境变量 | 默认值 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| issuer | `GENARRATIVE_JWT_ISSUER` | `https://auth.genarrative.local` | OIDC 风格发行者标识。 |
|
||||
| secret | `GENARRATIVE_JWT_SECRET` | `genarrative-dev-secret` | 当前阶段沿用对称签名密钥。 |
|
||||
| access token TTL | `GENARRATIVE_JWT_ACCESS_TOKEN_TTL_SECONDS` | `7200` | access token 有效期,单位秒。 |
|
||||
|
||||
兼容回退:
|
||||
|
||||
1. `issuer` 可回退读取 `JWT_ISSUER`。
|
||||
2. `secret` 可回退读取 `JWT_SECRET`。
|
||||
3. TTL 可回退读取 `JWT_EXPIRES_IN`,支持:
|
||||
- 纯秒值,例如 `900`
|
||||
- `s/m/h/d` 后缀,例如 `30m`、`2h`
|
||||
|
||||
## 6. 算法选择
|
||||
|
||||
当前阶段固定采用:
|
||||
|
||||
1. `alg = HS256`
|
||||
|
||||
理由:
|
||||
|
||||
1. 与当前 Node 基线兼容,迁移阻力最低。
|
||||
2. 先把 claims、配置口径和 Bearer 主链稳定下来。
|
||||
3. 若未来升级到非对称签名,应作为独立任务处理,而不是夹带进当前重写链路。
|
||||
|
||||
## 7. Rust 结构设计
|
||||
|
||||
### 7.1 `AccessTokenClaimsInput`
|
||||
|
||||
用途:
|
||||
|
||||
1. 作为业务层输入。
|
||||
2. 不承载 `iat/exp/iss` 这种平台计算字段。
|
||||
|
||||
字段:
|
||||
|
||||
1. `user_id`
|
||||
2. `session_id`
|
||||
3. `provider`
|
||||
4. `roles`
|
||||
5. `token_version`
|
||||
6. `phone_verified`
|
||||
7. `binding_status`
|
||||
8. `display_name`
|
||||
|
||||
### 7.2 `AccessTokenClaims`
|
||||
|
||||
用途:
|
||||
|
||||
1. 对应最终 JWT payload。
|
||||
2. 直接用于签名与验签结果输出。
|
||||
|
||||
字段:
|
||||
|
||||
1. `iss`
|
||||
2. `sub`
|
||||
3. `sid`
|
||||
4. `provider`
|
||||
5. `roles`
|
||||
6. `ver`
|
||||
7. `phone_verified`
|
||||
8. `binding_status`
|
||||
9. `display_name`
|
||||
10. `iat`
|
||||
11. `exp`
|
||||
|
||||
## 8. 校验规则
|
||||
|
||||
### 8.1 签发前校验
|
||||
|
||||
1. `issuer`、`secret` 不能为空。
|
||||
2. TTL 必须大于 `0`。
|
||||
3. `sub` 不能为空。
|
||||
4. `sid` 不能为空。
|
||||
5. `roles` 不能为空数组。
|
||||
6. `exp` 必须晚于 `iat`。
|
||||
|
||||
### 8.2 验签时校验
|
||||
|
||||
1. 算法必须是 `HS256`。
|
||||
2. 签名必须正确。
|
||||
3. `iss` 必须匹配当前配置。
|
||||
4. `exp/iat/iss/sub` 必须存在。
|
||||
5. 反序列化后的 `sid/provider/roles/ver/phone_verified/binding_status` 必须完整。
|
||||
|
||||
当前阶段不做的校验:
|
||||
|
||||
1. `ver` 与数据库最新 token version 比对。
|
||||
2. `sid` 与 `refresh_session` 活跃状态比对。
|
||||
3. `roles` 的细粒度授权判断。
|
||||
|
||||
## 9. api-server 最小接线
|
||||
|
||||
本阶段 `api-server` 接线规则如下:
|
||||
|
||||
1. `AppConfig` 增加 JWT 相关配置。
|
||||
2. `AppState` 在启动时构造唯一一份 `JwtConfig`。
|
||||
3. `require_bearer_auth` 中间件从请求头读取 Bearer token。
|
||||
4. 验签成功后把 claims 以 `AuthenticatedAccessToken` 写入 request extensions。
|
||||
5. 内部路由 `/_internal/auth/claims` 用于返回当前已校验 claims,作为阶段验收与调试入口。
|
||||
|
||||
说明:
|
||||
|
||||
1. 这个内部路由不是最终对外 contract。
|
||||
2. 它的存在是为了在 `module-auth` 与正式 `/api/auth/me` 落地前,先把 Bearer 主链单独跑通。
|
||||
|
||||
## 10. 测试策略
|
||||
|
||||
当前阶段要求至少覆盖:
|
||||
|
||||
1. `platform-auth` 的 JWT 签发与验签回环。
|
||||
2. issuer 不匹配时拒绝。
|
||||
3. 空角色拒绝。
|
||||
4. `api-server` 在无 Bearer token 时返回 `401`。
|
||||
5. `api-server` 在合法 Bearer token 下返回 claims。
|
||||
|
||||
## 11. 完成定义
|
||||
|
||||
当以下条件满足时,本任务视为完成:
|
||||
|
||||
1. Rust workspace 中存在真实可编译的 `platform-auth` crate。
|
||||
2. `api-server` 已能使用 `platform-auth` 校验 Bearer JWT。
|
||||
3. 工作区测试与编译可通过。
|
||||
4. 任务清单已同步更新。
|
||||
|
||||
## 12. 后续衔接
|
||||
|
||||
下一阶段继续衔接:
|
||||
|
||||
1. refresh cookie 读取与轮换。
|
||||
2. `module-auth` 会话真相与 `token_version` 在线校验。
|
||||
3. `/api/auth/me`、`/api/auth/refresh` 等正式接口。
|
||||
4. SpacetimeDB 对 Axum JWT 的身份透传验证。
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
## 文档列表
|
||||
|
||||
- [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` 迁移规则。
|
||||
- [SPACETIMEDB_WECHAT_AUTH_STATE_TABLE_DESIGN_2026-04-21.md](./SPACETIMEDB_WECHAT_AUTH_STATE_TABLE_DESIGN_2026-04-21.md):`M2` 第七张微信 OAuth 状态表 `wechat_auth_state` 的字段、过期/消费语义、`wechat/start` 与 `wechat/callback` 的单次消费规则,以及多实例下的清理策略。
|
||||
|
||||
Reference in New Issue
Block a user