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>
This commit is contained in:
liuyun 2026-10-10 23:23:56 +08:00
parent 802851a69f
commit 1790fb30a8
13 changed files with 142 additions and 1 deletions

View File

@ -0,0 +1,40 @@
# Audit Log Specification
## Purpose
定义操作日志(审计)的自动落库行为:写操作与登录/登出由装饰器与拦截器统一记录,异步写入不阻塞业务。
## Requirements
### Requirement: 写操作自动审计
系统 SHALL 对标注 `@AuditLog(module, action)` 的写接口(增/删/改)在请求完成后异步写入 sys_audit_log,记录操作人、模块、动作、请求方法、路径、入参、结果状态、IP、UA 与耗时。
#### Scenario: 写操作成功
- **WHEN** 标注 `@AuditLog` 的写接口执行成功
- **THEN** 系统写入一条 audit_log,status=success,含 module/action/method/path/user_id/username/ip/user_agent/duration_ms
#### Scenario: 写操作失败
- **WHEN** 标注 `@AuditLog` 的写接口执行失败
- **THEN** 系统写入一条 audit_log,status=fail,并记录 error_message
#### Scenario: 查询不审计
- **WHEN** 查询类(读)接口执行
- **THEN** 系统不写入审计日志
### Requirement: 登录登出审计
系统 SHALL 记录登录成功与登出事件到 audit_log(module=auth,action=login/logout)。
#### Scenario: 登录成功审计
- **WHEN** 用户登录成功
- **THEN** 系统写入 audit_log(module=auth, action=login, status=success)
#### Scenario: 登出审计
- **WHEN** 用户登出
- **THEN** 系统写入 audit_log(module=auth, action=logout)
### Requirement: 审计异步不阻塞
审计日志 SHALL 异步写入;写入失败仅告警,不得影响业务请求结果。
#### Scenario: 审计写入失败
- **WHEN** 审计日志写库失败
- **THEN** 系统记录告警日志,业务请求照常返回成功结果

View File

@ -0,0 +1,44 @@
# Auth Specification
## Purpose
定义后端三级鉴权的执行语义与超级管理员绕过规则,作为所有接口访问控制的统一契约。
## Requirements
### Requirement: 三级鉴权
系统 SHALL 对每个接口按三级放行:标注 `@Public` 的接口无需登录即可访问;未标注任何权限装饰器的接口仅校验有效登录态;标注 `@RequirePermissions` 的接口要求登录态且当前用户拥有对应权限码。
#### Scenario: 公开接口匿名访问
- **WHEN** 请求标注 `@Public` 的接口(如登录、刷新 token、接口文档)
- **THEN** 系统无需 token 即放行
#### Scenario: 未标注接口仅校验登录
- **WHEN** 未登录请求未标注权限装饰器的接口
- **THEN** 系统返回 401 未登录
#### Scenario: 未标注接口登录后放行
- **WHEN** 已登录用户请求未标注权限装饰器的接口
- **THEN** 系统放行
#### Scenario: 需权限接口无权限码
- **WHEN** 已登录用户请求 `@RequirePermissions('user:create')` 的接口,但其权限集不含 `user:create`
- **THEN** 系统返回 403 无权限
### Requirement: 权限集入上下文
登录成功 SHALL 将用户的权限码集合(其全部角色经资源关联聚合得到的 api/button 资源 code)载入请求上下文,供权限守卫校验。
#### Scenario: 登录聚合权限
- **WHEN** 用户登录成功
- **THEN** 系统按用户全部角色的 role_resource 关联聚合出权限码集合并载入上下文
### Requirement: 超级管理员绕过
拥有 `code=super_admin` 角色的用户 SHALL 绕过权限码校验;其列表查询的数据权限按「全部」处理,不受 data_scope 过滤。
#### Scenario: 超管访问任意需权限接口
- **WHEN** 拥有 `super_admin` 角色的用户请求任意 `@RequirePermissions` 接口
- **THEN** 系统无需校验其是否拥有该权限码即放行
#### Scenario: 超管查看全量数据
- **WHEN** 超管执行列表查询
- **THEN** 系统不做 data_scope 部门过滤,返回全量数据

View File

@ -0,0 +1,25 @@
# Login Log Specification
## Purpose
定义登录日志的自动落库行为:每次登录成功与失败均记录,失败附原因与来源信息。
## Requirements
### Requirement: 登录成功记录
系统 SHALL 在登录成功时写入 sys_login_log,记录 username、ip、user_agent、status=success。
#### Scenario: 登录成功
- **WHEN** 用户登录成功
- **THEN** 系统写入 login_log(username/ip/user_agent/status=success)
### Requirement: 登录失败记录
系统 SHALL 在登录失败时写入 sys_login_log,记录 username、ip、user_agent、status=fail 与失败原因 message。
#### Scenario: 密码错误
- **WHEN** 用户以错误密码登录失败
- **THEN** 系统写入 login_log,status=fail,message 说明密码错误
#### Scenario: 账号停用或锁定
- **WHEN** 停用或锁定账号尝试登录失败
- **THEN** 系统写入 login_log,status=fail,message 说明账号状态原因

View File

@ -0,0 +1,32 @@
# Resource Authorization Specification
## Purpose
定义资源表作为 RBAC 授权锚点的运行时语义:权限码即资源 code,采用细粒度 domain:action 命名。
## Requirements
### Requirement: 权限码即资源 code
系统 SHALL 以资源表的 `code` 作为接口与按钮的权限标识;`@RequirePermissions` 的参数 SHALL 为该 code 字符串。
#### Scenario: 接口声明权限码
- **WHEN** 接口声明 `@RequirePermissions('user:create')`
- **THEN** 系统校验当前用户权限集是否包含字符串 `user:create`
### Requirement: 权限码格式
权限码 SHALL 采用细粒度 `domain:action` 格式(domain 为域,action 为动作,如 `user:list`、`user:create`、`role:assign`)。
#### Scenario: 细粒度权限码
- **WHEN** 为「创建用户」接口登记权限码
- **THEN** 该接口资源 code 为 `user:create`
### Requirement: 权限码聚合来源
用户权限集 SHALL 由其全部角色的 role_resource 关联(role_code + resource_code),取其中 `type ∈ {button, api}` 的 resource.code 并集聚合得到。
#### Scenario: 多角色权限并集
- **WHEN** 用户拥有两个角色,各自关联了部分资源
- **THEN** 该用户权限集为两角色资源 code 的并集
#### Scenario: 菜单不计入接口权限集
- **WHEN** 用户角色关联了 `type=menu` 的资源
- **THEN** 该 menu 的 code 不进入接口权限集(菜单用于导航渲染,不用于接口鉴权)

@ -1 +1 @@
Subproject commit 7340658305de30b234bc87e0b5490e4c34a49b9a Subproject commit ce2aa35a24ab351433ae7bb98aba2cab38c7e676