# 脚手架审计整改清单 > 状态标记:`⬜ 待处理` · `🔶 需讨论` · `✅ 已决定` · `✔ 已完成` > 顺序按批次(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 会话与安全加固 - [x] **M5** 登录安全基线缺失 —— 无锁定/后端验证码/密码策略。✔ 已完成:失败锁定(5 次/15 分钟)+ 密码长度策略(验证码后置) - [x] **M7** Swagger 无鉴权 + CORS 全开 + 无 helmet/限流 —— ✔ 已完成:helmet + CORS 白名单(CORS_ORIGIN)+ Swagger 仅非生产 + @nestjs/throttler 限流 - [x] **M12** RefreshToken 哈希未校验 + 无清理 —— ✔ 已完成:refresh 校验 tokenHash(清理并入 L8) - [x] **M14** 401 强退后 authStore 失真 —— ✔ 已完成:auth store 增 reset,handler 同步清空 - [x] **M15** dictStore loaded 守卫无法刷新 —— ✔ 已完成:fetch 加 force 参数,字典页增删改后 force 刷新 - [x] **M20** 登录租户写死 touyun —— ✔ 已完成:登录按用户名自动探测租户,多租户返回候选由前端弹窗选择 - [x] **M3** created_by 全项目零写入 —— ✔ 已完成:BaseCrudService.create 注入 createdBy - [x] **L5** 登出审计 username 写 null —— ✔ 已完成:按 userId 回查真实 username - [x] **L7** useRequest loading 竞态 + ty-crud 重复请求 —— ✔ 已完成:useRequest 请求序号防竞态 + ty-crud 搜索/重置去重 - [x] **L8** 审计/登录日志、refresh_token 无清理任务 —— ✔ 已完成:@nestjs/schedule 定时清理(过期 token + 90 天前日志) ## P3 工程化契约 - [ ] **H12** e2e 必然失败 + 无业务测试 —— 方案:修 e2e + 补核心链路用例 - [x] **M2** 时间字段 ISO vs Unix 毫秒 —— ✔ 已完成:API 层统一 Unix 毫秒(TransformInterceptor 递归转换 + 前端类型 number) - [ ] **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