437 lines
13 KiB
Markdown
437 lines
13 KiB
Markdown
# user-system 修复执行计划(按 P0 / P1 / P2 排序)
|
||
|
||
**计划日期**:2026-05-30
|
||
**输入依据**:`docs/code-review/FULL_REVIEW_2026-05-30.md`
|
||
**目标**:修复本轮 review 暴露出的安全、正确性、测试与文档一致性问题,并形成新的可审计验证证据。
|
||
|
||
---
|
||
|
||
## 一、执行原则
|
||
|
||
1. **先修协议与契约,再修测试与文档**
|
||
- 先修 SSO / Swagger / 路由契约错误
|
||
- 再收敛测试与静态检查
|
||
2. **每一类问题修完都必须立即验证**
|
||
3. **文档只能反映已验证事实,不能提前宣称完成**
|
||
4. **对外可见契约必须单点真实**
|
||
- 路由
|
||
- Swagger
|
||
- 前端调用
|
||
- 测试断言
|
||
- 状态文档
|
||
5. **修复计划必须覆盖 review 报告中的全部问题**
|
||
- 不能只修“代表性问题”
|
||
- 必须处理系统性问题源头
|
||
|
||
---
|
||
|
||
## 二、P0 修复计划(必须最优先)
|
||
|
||
### P0-1:把空壳 Swagger 修成真实有效文档
|
||
|
||
#### 目标
|
||
让 `/swagger/*any` 对应的不是空 `paths`,而是真实可用 OpenAPI 文档。
|
||
|
||
#### 具体动作
|
||
1. 梳理 Swagger 生成入口与当前生成流程
|
||
2. 确认 `swag init` 或项目既定生成方式
|
||
3. 生成有效 `docs/swagger.go` / `docs/docs.go`
|
||
4. 校验 `paths` 非空
|
||
5. 校验至少以下路径存在:
|
||
- `/api/v1/auth/login`
|
||
- `/api/v1/auth/register`
|
||
- `/api/v1/admin/users/export`
|
||
- `/api/v1/users/{id}`
|
||
|
||
#### 验证
|
||
- 生成 Swagger
|
||
- 检查 `docs/swagger.go` 中 `paths` 非空
|
||
- 如可本地启动,验证 `/swagger/index.html` 与 `/swagger/doc.json` 可用
|
||
|
||
---
|
||
|
||
### P0-2:系统性修正 Swagger 注释与真实路由的漂移
|
||
|
||
> 这是对报告中“系统性契约漂移”的完整修复,不再只处理导入导出接口。
|
||
|
||
#### 目标
|
||
统一以下来源的 API 契约:
|
||
|
||
- `internal/api/router/router.go`
|
||
- `internal/api/handler/*.go` 中全部 `@Router`
|
||
- `docs/API.md`
|
||
- 前端调用与测试
|
||
- 生成后的 Swagger 文档
|
||
|
||
#### 具体动作
|
||
1. 全量审计并修复以下类别的 `@Router` 漂移:
|
||
- export/import:admin 路径
|
||
- refresh:`/refresh-token` → `/refresh`
|
||
- email-code login:`/login-by-email-code` → `/login/email-code`
|
||
- resend activation:`/resend-activation-email` → `/resend-activation`
|
||
- TOTP:`/auth/totp/*` → `/auth/2fa/*`
|
||
- captcha:`/captcha/*` → `/auth/captcha*`
|
||
- password reset:`/auth/password/*` → `/forgot-password` / `/reset-password` / phone 变体
|
||
- custom fields:`/fields/*` → `/custom-fields/*`
|
||
- logs:`/users/me/*logs` → `/logs/*/me`
|
||
- admins:`/users/admins` → `/admin/admins`
|
||
- users/me 绑定类接口:bind-email / bind-phone / social accounts
|
||
2. 修复 HTTP method 漂移:
|
||
- `AssignRoles`:`POST` → `PUT`
|
||
- `AssignPermissions`:`POST` → `PUT`
|
||
- `SetupTOTP`:注释 method 与真实 method 对齐
|
||
3. 对照 `router.go` 做一次全量注释-路由对账,直到关键差异清零
|
||
4. 更新 `docs/API.md` 中对应路径
|
||
5. 重新生成 Swagger 文档
|
||
|
||
#### 验证
|
||
- `go test ./internal/api/handler ./internal/api/router -count=1`
|
||
- 生成 Swagger 后检查关键路径与 method 全部正确
|
||
- 使用脚本或审查清单确认:关键业务路由不再存在注释/注册漂移
|
||
|
||
---
|
||
|
||
### P0-3:修复 SSO 授权码模式未绑定 `redirect_uri` 的问题
|
||
|
||
#### 目标
|
||
让 authorization code 与 client / redirect URI 形成强绑定。
|
||
|
||
#### 具体动作
|
||
1. 在 `internal/auth/sso.go` 的 `SSOSession` 中加入 `RedirectURI`
|
||
2. `GenerateAuthorizationCode(...)` 保存该字段
|
||
3. `Token(...)` 兑换令牌时校验:
|
||
- `session.ClientID == req.ClientID`
|
||
- `session.RedirectURI == req.RedirectURI`
|
||
4. 对不匹配场景返回明确错误
|
||
5. 为此补回归测试
|
||
|
||
#### 验证
|
||
- `go test ./internal/auth ./internal/api/handler -count=1`
|
||
- 增加测试覆盖:
|
||
- 正确 client + redirect_uri 成功
|
||
- 错误 redirect_uri 失败
|
||
- 错误 client_id 失败
|
||
|
||
---
|
||
|
||
### P0-4:禁用 implicit flow
|
||
|
||
#### 目标
|
||
系统只支持更安全的授权码模式,不再通过 fragment 返回 access token。
|
||
|
||
#### 具体动作
|
||
1. 修改 `internal/api/handler/sso_handler.go`
|
||
2. 对 `response_type=token`:
|
||
- 返回 `400 unsupported response_type`
|
||
- 或仅允许 `code`
|
||
3. 清理相应的宽松测试
|
||
4. 同步文档说明只支持 code flow
|
||
|
||
#### 验证
|
||
- `response_type=token` 应明确失败
|
||
- `response_type=code` 正常工作
|
||
|
||
---
|
||
|
||
### P0-5:重构 SSO 路由分组与鉴权模型,使 `/token`、`/introspect`、`/revoke`、`/userinfo` 语义正确
|
||
|
||
> 这是第二轮新增问题;若不修,P0-3/P0-4 仍不完整。
|
||
|
||
#### 目标
|
||
让 SSO/OAuth 相关端点符合正确的访问控制模型,而不是错误复用平台用户 BearerAuth。
|
||
|
||
#### 具体动作
|
||
1. 将 SSO 路由按语义拆分,不再整体挂在 `protected` 下
|
||
2. 至少区分:
|
||
- `/authorize`:需要当前平台登录用户完成授权
|
||
- `/token`:客户端凭证 + 授权码模型,不依赖当前平台 BearerAuth
|
||
- `/introspect`:客户端认证模型
|
||
- `/revoke`:客户端认证模型或 token-owner 受控模型,必须明确
|
||
- `/userinfo`:基于 SSO access token,而不是平台 JWT 上下文
|
||
3. 为 `/token`、`/introspect`、`/revoke` 设计明确的 client auth 机制
|
||
4. 修正 `UserInfo` 的 token 解析来源,不能继续直接读平台 auth middleware 的 `user_id`
|
||
5. 同步更新测试与文档
|
||
|
||
#### 验证
|
||
- `/token` 在无平台 BearerAuth、仅有正确 client/code 条件下可成功
|
||
- `/introspect` / `/revoke` 不接受任意平台登录用户代操作
|
||
- `/userinfo` 返回的是 SSO token subject,而不是平台当前 session user
|
||
|
||
---
|
||
|
||
## 三、P1 修复计划(紧随 P0)
|
||
|
||
### P1-1:修复 `go vet ./...` 失败并收口静态分析门禁
|
||
|
||
#### 目标
|
||
让项目重新具备诚实宣称 `go vet` 通过的资格。
|
||
|
||
#### 具体动作
|
||
1. 修复:
|
||
- `internal/api/handler/avatar_handler_test.go`
|
||
- `internal/api/handler/export_handler_test.go`
|
||
2. 所有 `resp` 使用前先检查 `err`
|
||
3. 扫描同类 helper/测试模式,避免只修报错行
|
||
|
||
#### 验证
|
||
- `go vet ./...`
|
||
- `go test ./... -count=1`
|
||
|
||
---
|
||
|
||
### P1-2:把宽松状态码测试改成严格契约测试
|
||
|
||
#### 目标
|
||
让测试真正约束行为,而不是“什么都算通过”。
|
||
|
||
#### 具体动作
|
||
1. 优先重写以下测试文件:
|
||
- `internal/api/handler/export_handler_test.go`
|
||
- `internal/api/handler/sso_handler_test.go`
|
||
2. 逐场景收紧断言:
|
||
- 未认证 → 401
|
||
- 未授权 → 403
|
||
- 参数错误 → 400
|
||
- 成功 → 200 / 302
|
||
3. 删除允许 `500` 的正常断言路径
|
||
4. 对有环境差异的场景,先修被测逻辑,再收紧测试
|
||
5. 针对 SSO 补充协议级回归测试:
|
||
- `/token` 不再被平台 BearerAuth 门禁误拦
|
||
- `/introspect` / `/revoke` 权限模型正确
|
||
- `/userinfo` 基于 SSO token,而不是平台 session
|
||
6. 对关键契约类 handler 增加“路由/方法/状态码固定断言”
|
||
|
||
#### 验证
|
||
- 受影响包 `go test -count=1`
|
||
- 必须确保断言收紧后仍稳定通过
|
||
|
||
---
|
||
|
||
### P1-3:强化 JWT secret 治理为启动硬门禁
|
||
|
||
#### 目标
|
||
让 release 模式下的 JWT 配置符合项目自身文档标准。
|
||
|
||
#### 具体动作
|
||
1. 明确 `config.Load()` 下的正常启动规则
|
||
2. 在 release/standard 服务路径中强制:
|
||
- secret 缺失 → fail fast
|
||
- weak secret → fail fast
|
||
3. 保留 `LoadForBootstrap()` 仅用于初始化场景
|
||
4. 增加配置单元测试
|
||
|
||
#### 验证
|
||
- `go test ./internal/config -count=1`
|
||
- 缺失/弱 secret 场景必须失败
|
||
|
||
---
|
||
|
||
### P1-4:接通用户状态 / 权限变更后的缓存失效链路
|
||
|
||
#### 目标
|
||
避免密码、状态、角色、权限变更后继续使用陈旧缓存。
|
||
|
||
#### 具体动作
|
||
1. 梳理以下写路径:
|
||
- `ChangePassword`
|
||
- `UpdateStatus`
|
||
- `BatchUpdateStatus`
|
||
- `AssignRoles`
|
||
- `DeleteAdmin`
|
||
- `AssignPermissions`
|
||
2. 设计缓存失效注入方式
|
||
- 推荐通过依赖注入引入失效能力
|
||
- 不要让 service 直接依赖具体 middleware 实现细节
|
||
3. 在写路径完成后主动失效:
|
||
- user_state
|
||
- user_perms
|
||
- 受影响角色下的用户权限缓存
|
||
|
||
#### 验证
|
||
- 增加回归测试:
|
||
- 改密码后旧 token / 旧状态缓存失效
|
||
- 改角色/权限后权限即时生效
|
||
|
||
---
|
||
|
||
### P1-5:清理拟真 secret 示例
|
||
|
||
#### 目标
|
||
恢复文档敏感边界清洁度。
|
||
|
||
#### 具体动作
|
||
1. 清理 `docs/archive/OAUTH_INTEGRATION.md` 中拟真值
|
||
2. 全仓搜索其它类似格式示例
|
||
3. 统一替换为显式占位符
|
||
|
||
#### 验证
|
||
- 搜索确认无拟真 secret 示例残留
|
||
|
||
---
|
||
|
||
## 四、P2 修复计划(在 P0/P1 收口后处理)
|
||
|
||
### P2-1:修复 `strconvAtoi` 吞错问题
|
||
|
||
#### 目标
|
||
非法 status 参数返回显式错误,而不是静默当作 0。
|
||
|
||
#### 动作
|
||
1. 修改 `internal/api/handler/export_handler.go` 中 `strconvAtoi`
|
||
2. 非数字输入返回 error
|
||
3. `ExportUsers` 中对非法 `status` 返回 400
|
||
4. 增加回归测试
|
||
|
||
#### 验证
|
||
- `status=abc` → 400
|
||
|
||
---
|
||
|
||
### P2-2:头像上传改为流式写盘
|
||
|
||
#### 目标
|
||
消除不必要的整块内存分配。
|
||
|
||
#### 动作
|
||
1. 用 `os.Create` + `io.Copy` 代替 `Read + WriteFile`
|
||
2. 保持现有 magic bytes 校验逻辑
|
||
3. 确保失败时清理半成品文件
|
||
|
||
#### 验证
|
||
- 头像上传相关测试通过
|
||
- 文件写入失败场景仍能回滚
|
||
|
||
---
|
||
|
||
### P2-3:头像上传响应改为明确 struct
|
||
|
||
#### 目标
|
||
让返回 schema 与注释一致。
|
||
|
||
#### 动作
|
||
1. 引入明确响应 struct
|
||
2. 更新 Swagger 注释 / handler 返回值
|
||
3. 同步前端类型
|
||
|
||
#### 验证
|
||
- 相关 handler test
|
||
- 前端编译通过
|
||
|
||
---
|
||
|
||
### P2-4:前端构建大 chunk 警告优化
|
||
|
||
#### 目标
|
||
降低主包体积,改善生产可维护性。
|
||
|
||
#### 动作
|
||
1. 识别大 chunk 页面
|
||
2. 做路由级动态拆分
|
||
3. 必要时拆分 antd 重型页面模块
|
||
|
||
#### 验证
|
||
- `npm run build`
|
||
- 观察 chunk 体积变化
|
||
|
||
---
|
||
|
||
## 五、修复计划完整性审核
|
||
|
||
本节用于确认:**计划是否覆盖 review 报告中的全部问题**。
|
||
|
||
| Review 问题 | 计划覆盖项 | 覆盖状态 |
|
||
|---|---|---|
|
||
| Swagger 空壳 | P0-1 | 已覆盖 |
|
||
| Swagger 注释与真实路由系统性漂移 | P0-2 | 已覆盖 |
|
||
| SSO code 未绑定 redirect_uri | P0-3 | 已覆盖 |
|
||
| SSO implicit flow | P0-4 | 已覆盖 |
|
||
| SSO `/token` `/introspect` `/revoke` `/userinfo` 鉴权模型错误 | P0-5 | 已覆盖 |
|
||
| 宽松状态码测试掩盖问题 | P1-2 | 已覆盖 |
|
||
| `go vet` 不通过 | P1-1 | 已覆盖 |
|
||
| JWT secret 硬门禁不足 | P1-3 | 已覆盖 |
|
||
| 状态 / 权限缓存失效未接入 | P1-4 | 已覆盖 |
|
||
| 拟真 secret 示例 | P1-5 | 已覆盖 |
|
||
| `strconvAtoi` 吞错 | P2-1 | 已覆盖 |
|
||
| 头像整块读入内存 | P2-2 | 已覆盖 |
|
||
| 头像响应 schema 漂移 | P2-3 | 已覆盖 |
|
||
|
||
### 审核结论
|
||
|
||
当前修复计划已经覆盖 review 报告中的**全部问题项**。
|
||
其中最关键的改进是:
|
||
|
||
- 不再把“Swagger 路由错误”视为单点问题,而是按**系统性契约漂移**处理
|
||
- 新增 P0-5,明确修复 SSO route group / auth model 的结构性错误
|
||
|
||
这两点补齐后,计划才具备“能够完整修复 review 报告问题”的条件。
|
||
|
||
---
|
||
|
||
## 六、推荐执行顺序
|
||
|
||
### 阶段 1:协议与契约止血
|
||
1. P0-5 修 SSO route group / auth model
|
||
2. P0-3 修 SSO code / redirect_uri 绑定
|
||
3. P0-4 禁 implicit flow
|
||
4. P0-2 系统性修正 Swagger 注释与真实路由漂移
|
||
5. P0-1 生成有效 Swagger
|
||
|
||
### 阶段 2:质量门禁与测试收口
|
||
6. P1-1 修复 `go vet`
|
||
7. P1-2 收紧 export / sso / 契约类 handler 测试
|
||
8. P1-3 强化 JWT secret 启动门禁
|
||
|
||
### 阶段 3:一致性与边界治理
|
||
9. P1-4 接通缓存失效链路
|
||
10. P1-5 清理拟真 secret 示例
|
||
|
||
### 阶段 4:实现质量优化
|
||
11. P2-1 修 status 参数吞错
|
||
12. P2-2 头像流式写盘
|
||
13. P2-3 头像响应 struct 化
|
||
14. P2-4 前端 chunk 优化
|
||
|
||
---
|
||
|
||
## 七、每阶段完成后的最小验证矩阵
|
||
|
||
### P0 阶段后
|
||
```bash
|
||
go test ./internal/auth ./internal/api/handler ./internal/api/router -count=1
|
||
go build ./cmd/server
|
||
```
|
||
并检查 Swagger 生成结果。
|
||
|
||
### P1 阶段后
|
||
```bash
|
||
go vet ./...
|
||
go test ./... -count=1
|
||
go build ./cmd/server
|
||
cd frontend/admin && env -u NODE_ENV npm run test:run
|
||
cd frontend/admin && env -u NODE_ENV npm run build
|
||
```
|
||
|
||
### P2 阶段后
|
||
按受影响范围重跑:
|
||
|
||
```bash
|
||
go test ./internal/api/handler ./internal/service ./internal/repository -count=1
|
||
cd frontend/admin && env -u NODE_ENV npm run build
|
||
```
|
||
|
||
---
|
||
|
||
## 八、完成标准
|
||
|
||
只有同时满足以下条件,才能把本轮问题标记为“已收口”:
|
||
|
||
1. SSO code flow 绑定完整,implicit flow 已禁用
|
||
2. SSO `/token`、`/introspect`、`/revoke`、`/userinfo` 的访问控制模型正确
|
||
3. Swagger 文档非空且关键路径正确
|
||
4. 注释 / 路由 / 文档 / 前端 / 测试中的 API 契约一致
|
||
5. `go vet ./...` 通过
|
||
6. handler 关键测试不再接受互斥状态码混过
|
||
7. JWT secret 治理与项目文档标准一致
|
||
8. 缓存失效链路有真实接入与回归测试
|
||
9. 状态文档与 README 只保留已验证事实
|