liuyun 1790fb30a8 chore(openspec): archive close-phase-0, sync backend specs to main
- 归档 close-phase-0(RBAC 权限 + 审计/登录日志 + seed 收口)
- 新增主 spec:backend/auth、backend/res、backend/audit、backend/login
- 追踪 sysmgr-nest passwordHash 泄漏修复

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-10 23:23:56 +08:00

3.7 KiB
Raw Blame History

1. Redis 接入与权限模型(auth 域)

  • 1.1 引入 ioredis 依赖,封装 RedisService(get/set/del/按前缀 SCAN 删除),连接用 env(REDIS_HOST/PORT/DB/PASSWORD、REDIS_KEY_PREFIX,默认 127.0.0.1:6379、sysmgr:)
  • 1.2 auth.service 登录/刷新时聚合权限码集(user_role → role_resource → resource,取 type ∈ {button, api} 的 code)与 super 标志(是否绑定 code=super_admin),写入 Redis {prefix}perm:{tenantCode}:{userId}(TTL 随会话,刷新续期);登出删除
  • 1.3 jwt-auth.guard 校验通过后将 userId/tenantCode/username 装入 request.user(JWT 不放权限集)
  • 1.4 permissions.guard 从 Redis 读 {super, permissions}:super=true 直接放行;否则校验权限集是否包含全部所需权限码,缺一返回 403
  • 1.5 data_scope 过滤对 super=true 按「全部」处理(resolveDataScope 或各列表查询入口统一短路)
  • 1.6 授权变更失效:roles 模块改 role_resource / user_role 后删除该租户权限缓存(SCAN {prefix}perm:{tenantCode}:*)

2. 权限码挂接口

  • 2.1 定义各域权限码常量清单(domain:action):tenant/user/role/resource/org/dict/config/audit/login-log 的 list/create/update/delete 等
  • 2.2 tenants、users、roles、resources、orgs、dicts、configs 各 controller 的全部受控接口挂 @RequirePermissions(...)(写操作强制;list 按 domain:list 挂)
  • 2.3 audit-logs、login-logs 查询接口挂 audit:list / login-log:list
  • 2.4 登录/刷新/登出及 /docs 保持 @Public,无需权限码

3. 审计日志落库

  • 3.1 新增 @AuditLog(module, action) 装饰器(SetMetadata 记录 module/action)
  • 3.2 新增 AuditLogInterceptor:请求进入时快照 tenantCode/userId/username/ip/userAgent/method/path/脱敏 body 与起始时间;完成后异步 fire-and-forget 写入;异常时记告警不阻塞
  • 3.3 新增 AuditLogService:写 sys_audit_log(显式传 tenantCode,复用 BodyLogging 脱敏)
  • 3.4 注册 AuditLogInterceptor(全局);给各写接口 controller 挂 @AuditLog(domain, action)
  • 3.5 登录成功/登出写 audit_log(module=auth,action=login/logout)

4. 登录日志落库

  • 4.1 新增 LoginLogService:写 sys_login_log(username/ip/user_agent/status/message)
  • 4.2 auth.service.login 成功分支写 status=success;失败分支写 status=fail + message(密码错误/账号停用/锁定/租户不存在),并附 IP/UA

5. seed 脚本

  • 5.1 新增 prisma/seed.ts:裸 PrismaClient,按唯一键 upsert,可重复执行
  • 5.2 生成租户 touyun、根组织、角色 super_admin(data_scope=all)、用户 touyun(bcryptjs 哈希 Touyun@123)并绑定 super_admin
  • 5.3 生成全量资源树:菜单(工作台 + 各域导航)、api(每个受控接口一个,code=domain:action,含 method/api_path)、button(纯前端按钮)
  • 5.4 role_resource 将 super_admin 关联全部资源 code
  • 5.5 package.json 增加 seed 脚本(prisma db seed 配置)并跑通

6. 验证

  • 6.1 跑 seed 后以 touyun / Touyun@123 登录成功,Redis 中生成 {prefix}perm:touyun:{userId} 缓存(含 permissions/super)
  • 6.2 超管访问受控接口放行、列表查询全量;新建一个无权限的普通用户访问受控接口返回 403
  • 6.3 修改某角色授权(role_resource)后,该租户权限缓存被删除,受影响用户下一次请求按新权限生效
  • 6.4 写操作后 sys_audit_log 有记录(status/params 脱敏);登录成功/失败后 sys_login_log 有记录(失败含原因)
  • 6.5 回归:登录/刷新/登出、现有 CRUD、日志输出均正常;测试后停止服务