docs(plan): capture auth convergence rollout
Add the auth implementation convergence notes for gateway and supply-api, record the agreed rollout strategy in the execution log, and mark P1-C-01 through P1-C-06 complete in the master plan.
This commit is contained in:
181
docs/plans/2026-04-21-auth-implementation-convergence-notes.md
Normal file
181
docs/plans/2026-04-21-auth-implementation-convergence-notes.md
Normal file
@@ -0,0 +1,181 @@
|
||||
# 2026-04-21 Auth Implementation Convergence Notes
|
||||
|
||||
## 1. 输入范围
|
||||
|
||||
- `gateway/internal/app/bootstrap.go`
|
||||
- `gateway/internal/middleware/remote_runtime.go`
|
||||
- `gateway/internal/config/config.go`
|
||||
- `supply-api/internal/middleware/auth.go`
|
||||
- `supply-api/internal/app/runtime.go`
|
||||
- `supply-api/internal/app/bootstrap.go`
|
||||
- `supply-api/internal/httpapi/supply_api.go`
|
||||
- `supply-api/internal/middleware/ratelimit.go`
|
||||
|
||||
## 2. P1-C-01 gateway 入口与分支
|
||||
|
||||
### 2.1 token runtime 装配入口
|
||||
|
||||
来源:`gateway/internal/app/bootstrap.go:17`
|
||||
|
||||
1. `BuildServer` 在 `gateway/internal/app/bootstrap.go:42` 调用 `buildTokenRuntime(normalized.Auth)`。
|
||||
2. `buildTokenRuntime` 在 `gateway/internal/app/bootstrap.go:157` 按 `cfg.TokenRuntimeMode` 分支:
|
||||
- `inmemory` 路径:`gateway/internal/app/bootstrap.go:162`
|
||||
- `remote_introspection` 路径:`gateway/internal/app/bootstrap.go:164`
|
||||
3. `BuildServer` 把返回值同时注入 `Verifier` 和 `StatusResolver`,见 `gateway/internal/app/bootstrap.go:47`。
|
||||
|
||||
### 2.2 调用点
|
||||
|
||||
1. `BuildMux` 在 `gateway/internal/app/bootstrap.go:81` 和 `gateway/internal/app/bootstrap.go:82` 用 `BuildTokenAuthChain` 包装聊天与补全入口。
|
||||
2. `remote_introspection` 实际 HTTP 调用发生在 `gateway/internal/middleware/remote_runtime.go:56`。
|
||||
3. introspection 请求目标固定为 `/api/v1/platform/tokens/introspect`,见 `gateway/internal/middleware/remote_runtime.go:63`。
|
||||
|
||||
结论:
|
||||
|
||||
1. gateway 的 authority 选择点只在 `buildTokenRuntime` 一处,适合集中收口。
|
||||
2. 运行时真正消费远程 principal 的只有 `RemoteTokenRuntime.Verify`,切换面相对小。
|
||||
|
||||
## 3. P1-C-02 supply-api 的 JWT 校验、状态检查与 principal 注入点
|
||||
|
||||
### 3.1 JWT 校验
|
||||
|
||||
1. `BearerExtractMiddleware` 在 `supply-api/internal/middleware/auth.go:275` 提取 Bearer token,并在 `supply-api/internal/middleware/auth.go:315` 写入 `bearerTokenKey`。
|
||||
2. `TokenVerifyMiddleware` 在 `supply-api/internal/middleware/auth.go:322` 启动完整鉴权链。
|
||||
3. 真正的 JWT 解析发生在 `supply-api/internal/middleware/auth.go:515`,通过 `jwt.ParseWithClaims` 解析 `TokenClaims`。
|
||||
|
||||
### 3.2 token 状态检查
|
||||
|
||||
1. `TokenVerifyMiddleware` 在 `supply-api/internal/middleware/auth.go:389` 调用 `m.checkTokenStatus(r.Context(), claims.ID)`。
|
||||
2. `checkTokenStatus` 最终走 `m.tokenBackend.CheckTokenStatus`,见 `supply-api/internal/middleware/auth.go:596` 和 `supply-api/internal/middleware/auth.go:606`。
|
||||
|
||||
### 3.3 principal 注入
|
||||
|
||||
1. JWT claims 写入 context 的位置在 `supply-api/internal/middleware/auth.go:428`。
|
||||
2. `tenant_id` 注入点在 `supply-api/internal/middleware/auth.go:429`。
|
||||
3. `operator_id` 注入点在 `supply-api/internal/middleware/auth.go:430`。
|
||||
|
||||
结论:
|
||||
|
||||
1. `supply-api` 目前仍然自己承担 JWT authority: 解析、验签、状态查询、principal 注入都在本地完成。
|
||||
2. 如果要迁到 principal consumer,关键收口点就是 `TokenVerifyMiddleware` 和 `checkTokenStatus`。
|
||||
|
||||
## 4. P1-C-03 supply-api token backend 装配点
|
||||
|
||||
### 4.1 DB-backed / memory-backed store 装配
|
||||
|
||||
1. `buildStoreBundle` 在 `supply-api/internal/app/runtime.go:286` 按 `db != nil` 分支:
|
||||
- DB-backed:`supply-api/internal/app/runtime.go:287`
|
||||
- memory-backed:`supply-api/internal/app/runtime.go:295`
|
||||
2. `buildDBStoreBundle` 在 `supply-api/internal/app/runtime.go:302` 创建 `tokenStatusRepo`。
|
||||
3. memory bundle 不创建 `tokenStatusRepo`,见 `supply-api/internal/app/runtime.go:321`。
|
||||
|
||||
### 4.2 token backend 与鉴权中间件装配
|
||||
|
||||
1. `buildSecurityBundle` 在 `supply-api/internal/app/runtime.go:332` 统一装配鉴权依赖。
|
||||
2. DB-backed token backend 分支在 `supply-api/internal/app/runtime.go:344` 到 `supply-api/internal/app/runtime.go:348`。
|
||||
3. memory-backed token backend 分支在 `supply-api/internal/app/runtime.go:349` 到 `supply-api/internal/app/runtime.go:351`。
|
||||
4. `NewAuthMiddleware` 的装配位置在 `supply-api/internal/app/runtime.go:355`。
|
||||
|
||||
### 4.3 HTTP 启动链路
|
||||
|
||||
1. 非 `dev` 环境必须有 `AuthMiddleware`,见 `supply-api/internal/app/bootstrap.go:108`。
|
||||
2. 真正的 middleware 链在 `supply-api/internal/app/bootstrap.go:167` 开始构建。
|
||||
3. 非 `dev` 环境当前固定接入:
|
||||
- `QueryKeyRejectMiddleware`:`supply-api/internal/app/bootstrap.go:178`
|
||||
- `BearerExtractMiddleware`:`supply-api/internal/app/bootstrap.go:177`
|
||||
- `TokenVerifyMiddleware`:`supply-api/internal/app/bootstrap.go:176`
|
||||
|
||||
结论:
|
||||
|
||||
1. `supply-api` 的 token authority 不是散落的,而是通过 `buildSecurityBundle` 和 `buildMiddlewareChain` 这两处装配成型。
|
||||
2. DB-backed 与 memory-backed 的切换目前只影响 token 状态后端,不影响本地 JWT 验签语义。
|
||||
|
||||
## 5. P1-C-04 gateway 非 dev 禁用本地 authority 改动清单
|
||||
|
||||
### 5.1 `config`
|
||||
|
||||
1. 收紧 `gateway/internal/config/config.go:225` 的 `ValidateAuthConfig`:
|
||||
- 从“仅 `prod` / `staging` 禁用 `inmemory`”改为“只要 `env != dev` 就禁用 `inmemory`”。
|
||||
- 保证 `qa`、`pre`、`demo`、`online` 等共享环境也不能漏过。
|
||||
2. 调整 `gateway/internal/config/config.go:170` 的默认值策略:
|
||||
- `dev` 允许默认 `inmemory`
|
||||
- 非 `dev` 环境必须显式配置 `remote_introspection`
|
||||
|
||||
### 5.2 `bootstrap`
|
||||
|
||||
1. 给 `gateway/internal/app/bootstrap.go:157` 的 `buildTokenRuntime` 增加环境级兜底校验,避免绕过 `ValidateAuthConfig` 后仍能落到 `inmemory` 分支。
|
||||
2. 审视 `gateway/internal/app/bootstrap.go:217` 的默认值写入,避免 normalize 之后把共享环境误归到 `inmemory`。
|
||||
3. 保持 `gateway/internal/middleware/remote_runtime.go:56` 为唯一非 `dev` 认证入口,不再保留第二条本地 authority 路径。
|
||||
|
||||
### 5.3 `tests`
|
||||
|
||||
1. 扩展 `gateway/internal/config/config_test.go`:
|
||||
- 增加 `qa` / `demo` / `online` 等非 `dev` 环境禁用 `inmemory` 的用例。
|
||||
2. 扩展 `gateway/internal/app/bootstrap_test.go`:
|
||||
- 校验非 `dev` 环境传入 `inmemory` 时构建失败。
|
||||
3. 扩展 `gateway/internal/middleware/remote_runtime_test.go`:
|
||||
- 校验远程 introspection 新字段收敛后仍能正确反序列化 principal。
|
||||
|
||||
## 6. P1-C-05 supply-api 从 JWT authority 迁到 principal consumer 的改动清单
|
||||
|
||||
### 6.1 `middleware`
|
||||
|
||||
1. 把 `TokenClaims` 从“JWT claims”收敛为“canonical principal”模型,降低对本地 JWT 结构的耦合。
|
||||
2. 在 `supply-api/internal/middleware/auth.go` 替换本地 `verifyToken` + `checkTokenStatus` 组合:
|
||||
- 不再本地验签 JWT
|
||||
- 不再通过 `tokenBackend` 查询 token 状态
|
||||
- 改为消费来自 gateway / 上游 trusted hop 的 canonical principal
|
||||
3. 保留 `QueryKeyRejectMiddleware`、scope / role 授权与 context 注入,但输入从 JWT claims 改成 principal。
|
||||
|
||||
### 6.2 `runtime`
|
||||
|
||||
1. 收缩 `supply-api/internal/app/runtime.go:332` 的 `buildSecurityBundle`:
|
||||
- 删除 DB-backed / memory-backed token status backend 的双轨装配
|
||||
- 把安全装配收敛为 principal consumer middleware + 审计适配器
|
||||
2. 移除 `tokenStatusRepo` 对 auth 装配的硬依赖,让 DB 是否可用不再决定 authority 语义。
|
||||
|
||||
### 6.3 `HTTP handler`
|
||||
|
||||
1. 保持 handler 只依赖 context 中的 principal 字段,不依赖 JWT 细节:
|
||||
- `supply-api/internal/httpapi/supply_api.go:111` 的 `resolveSupplierID`
|
||||
- `supply-api/internal/middleware/ratelimit.go:233` 的租户限流键
|
||||
- `supply-api/internal/middleware/idempotency.go:280` 的 tenant/operator 注入消费者
|
||||
2. 审核所有直接读取 `GetTokenClaims` 的调用点,改为读取统一 principal / tenant / operator 上下文。
|
||||
|
||||
### 6.4 `tests`
|
||||
|
||||
1. `supply-api/internal/middleware/auth_test.go`
|
||||
- 从 JWT 验签场景改为 principal 消费场景
|
||||
- 增加缺 principal、principal 不完整、scope / role 拒绝的断言
|
||||
2. `supply-api/internal/app/runtime_test.go`
|
||||
- 删除 token backend 双轨装配前提
|
||||
- 新增 principal consumer middleware 装配断言
|
||||
3. `supply-api/internal/httpapi/supply_api_test.go`
|
||||
- 验证 handler 继续只依赖 context 中的 tenant / operator
|
||||
|
||||
## 7. P1-C-06 过渡期兼容策略
|
||||
|
||||
策略:`单写 + 双读短窗 + 一次性切断旧 JWT`
|
||||
|
||||
### 7.1 单写
|
||||
|
||||
1. token 生命周期只允许 `platform-token-runtime` 写入和解释。
|
||||
2. gateway 只通过 `remote_introspection` 获取 canonical principal。
|
||||
|
||||
### 7.2 双读短窗
|
||||
|
||||
1. 过渡期让 `supply-api` 优先读取新 principal 通道。
|
||||
2. 仅在 trusted internal 流量下保留旧 JWT 读取兜底,用于灰度和回滚。
|
||||
3. 双读期间禁止新增任何本地 token 签发 / 刷新 / 吊销逻辑。
|
||||
|
||||
### 7.3 一次性切断
|
||||
|
||||
1. 当 gateway 与 supply-api 的 principal 通道通过回归验证后,移除:
|
||||
- `verifyToken`
|
||||
- `tokenBackend`
|
||||
- 本地 JWT claims 依赖
|
||||
2. 切断后仅保留 principal consumer 路径,避免长期双轨。
|
||||
|
||||
为什么不用长期双轨:
|
||||
|
||||
1. 长期双轨会让 authority 再次分叉,和 Phase 1 目标冲突。
|
||||
2. 运维上会多一套签名密钥、状态后端和回归矩阵,违背“运维更简单”。
|
||||
@@ -69,3 +69,11 @@ rg -n "IntrospectTokenResponse|tenant_id|project_id|operator_id|metadata|IssueTo
|
||||
1. 已创建 `docs/plans/2026-04-21-token-runtime-schema-alignment-notes.md`,记录 schema、model、runtime store、audit store 的字段差异。
|
||||
2. 单一决策为“保留字段并贯穿”,不采用删除字段 / shrink SQL 路线。
|
||||
3. 后续实现顺序固定为:`model -> store -> API -> audit -> tests`。
|
||||
|
||||
## P1-C 身份实现收敛策略
|
||||
|
||||
执行结果:
|
||||
|
||||
1. 已创建 `docs/plans/2026-04-21-auth-implementation-convergence-notes.md`,记录 gateway 与 supply-api 的身份入口、装配点和迁移清单。
|
||||
2. gateway 侧后续只保留 `remote_introspection` 作为非 `dev` 环境 authority 入口,本地 `inmemory` 仅允许 `dev`。
|
||||
3. supply-api 侧过渡策略固定为:`单写 + 双读短窗 + 一次性切断旧 JWT`。
|
||||
|
||||
@@ -246,17 +246,17 @@
|
||||
- Modify: `supply-api/internal/app/runtime.go`
|
||||
- Modify: `supply-api/internal/app/bootstrap.go`
|
||||
|
||||
- [ ] `P1-C-01` 在 `gateway/internal/app/bootstrap.go` 标出 `inmemory` 与 `remote_introspection` 分支。
|
||||
- [x] `P1-C-01` 在 `gateway/internal/app/bootstrap.go` 标出 `inmemory` 与 `remote_introspection` 分支。
|
||||
完成标准:分支入口和调用点被记录。
|
||||
- [ ] `P1-C-02` 在 `supply-api/internal/middleware/auth.go` 标出 JWT 验证、token 状态检查和 principal 注入点。
|
||||
- [x] `P1-C-02` 在 `supply-api/internal/middleware/auth.go` 标出 JWT 验证、token 状态检查和 principal 注入点。
|
||||
完成标准:三个位置都被记录。
|
||||
- [ ] `P1-C-03` 在 `supply-api/internal/app/runtime.go` 标出 token backend 的装配点。
|
||||
- [x] `P1-C-03` 在 `supply-api/internal/app/runtime.go` 标出 token backend 的装配点。
|
||||
完成标准:DB-backed 与 memory-backed 装配点均被记录。
|
||||
- [ ] `P1-C-04` 写出 `gateway` 非 dev 禁用本地 authority 的代码改动清单。
|
||||
- [x] `P1-C-04` 写出 `gateway` 非 dev 禁用本地 authority 的代码改动清单。
|
||||
完成标准:至少包含 config、bootstrap、tests。
|
||||
- [ ] `P1-C-05` 写出 `supply-api` 从“JWT authority”迁到“principal consumer”的代码改动清单。
|
||||
- [x] `P1-C-05` 写出 `supply-api` 从“JWT authority”迁到“principal consumer”的代码改动清单。
|
||||
完成标准:至少包含 middleware、runtime、HTTP handler、tests。
|
||||
- [ ] `P1-C-06` 写出过渡期兼容策略。
|
||||
- [x] `P1-C-06` 写出过渡期兼容策略。
|
||||
完成标准:明确单写、双读、切流或一次性切换的方案。
|
||||
- [ ] `P1-C-07` 写出回滚条件。
|
||||
完成标准:明确何时回滚、回滚到哪一版契约。
|
||||
|
||||
Reference in New Issue
Block a user