# 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 只保留已验证事实