System_Management/docs/audit-checklist.md
liuyun 5038b43d18 docs: 审计清单 M20 完成(track 前后端)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-11 16:41:26 +08:00

64 lines
7.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 脚手架审计整改清单
> 状态标记:`⬜ 待处理` · `🔶 需讨论` · `✅ 已决定` · `✔ 已完成`
> 顺序按批次(P0 安全堵漏 → P1 RBAC 闭环 → P2 会话加固 → P3 工程化契约)推进,序号即处理顺序,可调。
## P0 安全越权堵漏
- [x] **C1** 跨租户越权 —— Tenant 表无租户过滤,任意租户超管可管全平台租户。✔ 已完成:`super_admin`=平台超管(保留)、`tenant_super_admin`=租户顶层(保留),`tenant:*` 仅平台租户可授予(constants.ts + roles.service 保留码校验 + 平台级权限剥离)
- [x] **H1** 软删与唯一约束冲突 —— 删后无法重建同名 → P2002 → 500。✔ 已完成:方案 B(BaseCrudService.softRemove 改名回收 `#id`,按列长截断)+ P2002→409
- [x] **H2** 删除角色不清理关联与缓存 —— user_role/role_resource/role_org 残留,聚合不校验已删角色。✔ 已完成:removeRole 级联清理 + 清缓存 + 保留角色禁删 + resolveAuth 过滤已删角色
- [x] **H3** 权限聚合缺 status 过滤 —— 停用资源仍被授权。✔ 已完成:resolveAuth 资源查询补 `status='enabled'`
- [x] **H4** 用户停用/删除后旧 token 仍可用 —— 守卫不查用户状态,缓存 TTL=7 天。✔ 已完成:方案 A(tokenVersion)+ JwtAuthGuard 每请求校验 + Redis 用户状态缓存
- [x] **H5** 重置密码不吊销会话 —— refresh token 不撤销。✔ 已完成:并入 H4,resetPassword/停用/删除 → invalidateSessions(tokenVersion++ + 删 refresh + 清缓存)
- [x] **H6** 角色资源树半选回显导致权限放大 —— 半选父节点被持久化 + 回显级联全选。✔ 已完成:只保存叶子键 `getCheckedKeys(true)` + 回显 `setCheckedKeys(assigned, true)`
- [x] **H10** 401 自动刷新无限循环 —— login/refresh 自身 401 也进刷新重放。✔ 已完成:`_retry` 标记 + 排除 login/refresh + 失败 reject
- [x] **H11** data_scope self 语义错误 —— self 等同本部门;详情接口无数据权限。✔ 已完成:self 按 userId 过滤 + 详情 assertCanView 403
- [x] **H13** seed 幂等副作用 —— 重跑重置管理员密码/启用账号。✔ 已完成:update 分支剥离 password/status
- [x] **M1** 日志脱敏不含 phone/email —— 违反 spec 安全红线。✔ 已完成:mask.ts 补充 phone/mobile/email
- [x] **M6** JWT 密钥默认兜底值 —— 生产忘配置即可伪造 token。✔ 已完成:缺失/生产弱密钥直接拒绝启动
- [x] **M8** pageSize 无上限 —— 可拉全表。✔ 已完成:`@Max(200)`
- [x] **M9** DTO 枚举缺校验 —— status 裸 `@IsString`。✔ 已完成:全 DTO 加 `@IsIn`(UserStatus/CommonStatus/DataScope/ResourceType)
- [x] **M10** Prisma 错误未映射 —— P2002/P2025 原文泄漏且 500。✔ 已完成:P2002→409、P2025→404、未知异常不泄漏内部细节
- [x] **M11** assignResources 非事务 + 不校验 + :id 语义混淆 —— ✔ 已完成:事务化 + 角色存在性校验(:id 实为 roleCode,已注释说明)
- [x] **M22** super_admin 可被租户自建 —— ✔ 已完成:并入 C1,`RESERVED_ROLE_CODES` 校验(super_admin / tenant_super_admin)
- [x] **M4** 组织树可成环 —— collectDescendants 死循环。✔ 已完成:create/update 防环校验 + collectDescendants visited 集合
## P1 RBAC 闭环
- [x] **H7** 用户-角色分配缺失 —— 无端点/DTO/UI。✔ 已完成:`GET/PUT /users/:id/roles` + DTO + 前端分配角色表单 + 用户页入口
- [x] **H9** 按钮级权限未实现 —— 无下发接口/指令,导出按钮不存在。✔ 核心已完成:`/auth/permissions` 下发 + permission store + `v-permission` 指令 + ty-crud 权限过滤 + 用户页导出演示(role/audit/login-log 3 个导出按钮为同模式,待补)
- [x] **M18** 前端无路由级权限过滤 + 403 页 —— ✔ 已完成:路由守卫按可访问菜单 path 过滤 + 403 页(/403)
- [x] **M21** 数据权限覆盖面过窄 —— 仅用户列表。✔ 已完成(方案 A):组织树按可见部门过滤 + 审计/登录日志按操作人部门过滤;角色/字典/配置保持租户级
- [x] **H8** 注册/忘记密码是假功能 —— mock 假成功。✔ 已完成:注册真实化(POST /auth/register),注册/忘记密码默认隐藏(showRegister/showForgetPassword=false,fork 可开启)
- [x] **M17** 租户 onboarding 断裂 —— 新建租户不可用、删除留孤儿。✔ 已完成:initTenant 模板(根组织+tenant_super_admin+管理员+资源+字典+授权)+ 删除级联清理;顺带修复 BaseCrudService tenant 大小写注入 bug
- [x] **新增** 用户自助修改密码/个人资料 —— 缺失清单。✔ 已完成:PATCH /auth/me/password(校验原密码 + 吊销其它会话)+ 顶栏「修改密码」入口
## P2 会话与安全加固
- [ ] **M5** 登录安全基线缺失 —— 无锁定/后端验证码/密码策略。方案:先锁定+密码策略,验证码后置
- [ ] **M7** Swagger 无鉴权 + CORS 全开 + 无 helmet/限流 —— 方案:/docs 收口 + CORS 白名单 + helmet + 限流
- [ ] **M12** RefreshToken 哈希未校验 + 无清理 —— 方案:校验 hash + 过期清理任务
- [ ] **M14** 401 强退后 authStore 失真 —— 方案:handler 里同步重置 authStore
- [ ] **M15** dictStore loaded 守卫无法刷新 —— 方案:fetch 加 force 参数
- [x] **M20** 登录租户写死 touyun —— ✔ 已完成:登录按用户名自动探测租户,多租户返回候选由前端弹窗选择
- [ ] **M3** created_by 全项目零写入 —— 方案:BaseCrudService.create 注入 created_by
- [ ] **L5** 登出审计 username 写 null —— 方案:写入真实 username
- [ ] **L7** useRequest loading 竞态 + ty-crud 重复请求 —— 方案:请求序号/去重
- [ ] **L8** 审计/登录日志、refresh_token 无清理任务 —— 方案:定时清理任务
## P3 工程化契约
- [ ] **H12** e2e 必然失败 + 无业务测试 —— 方案:修 e2e + 补核心链路用例
- [ ] **M2** 时间字段 ISO vs Unix 毫秒 —— 方案:API 层转 Unix 毫秒(🔶 需讨论,见 D4)
- [ ] **M16** vite `olldownOptions` 拼写错误 —— 方案:改 `rolldownOptions`
- [ ] **M19** 前端 .env/.env.dev 入库 + .env.example 带像真密码 —— 方案:gitignore + 模板脱敏
- [ ] **L1** 模板残留/无 LICENSE/stats.html 入库 —— 方案:清理 + 补 LICENSE
- [ ] **L2** 启动 console.log 噪音 —— 方案:移除
- [ ] **L3** docs/requirements 空目录 + config/menu.ts 死代码 —— 方案:清理
- [ ] **L4** README 克隆命令与子模块风格不一致 —— 方案:统一
- [ ] **L6** ty-crud 取消确认 rejection 未捕获 —— 方案:catch
- [ ] **L9** @nestjs/mau 非常规依赖 —— 方案:核实来源/用途
- [ ] **L10** 无 CI/Dockerfile/compose 部署编排 —— 方案:补 CI + 部署物料
- [ ] **新增** spec 覆盖补全 —— users/roles/orgs/tenants/configs 与前端多页无 spec 锚点。方案:补主 spec