From 1790fb30a809eeec589d0be58bb367df49de75bf Mon Sep 17 00:00:00 2001 From: liuyun Date: Sat, 10 Oct 2026 23:23:56 +0800 Subject: [PATCH] chore(openspec): archive close-phase-0, sync backend specs to main MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 归档 close-phase-0(RBAC 权限 + 审计/登录日志 + seed 收口) - 新增主 spec:backend/auth、backend/res、backend/audit、backend/login - 追踪 sysmgr-nest passwordHash 泄漏修复 Co-Authored-By: Claude Opus 4.8 --- .../2026-10-10-close-phase-0}/.openspec.yaml | 0 .../2026-10-10-close-phase-0}/design.md | 0 .../2026-10-10-close-phase-0}/proposal.md | 0 .../specs/backend/audit/spec.md | 0 .../specs/backend/auth/spec.md | 0 .../specs/backend/login/spec.md | 0 .../specs/backend/res/spec.md | 0 .../2026-10-10-close-phase-0}/tasks.md | 0 openspec/specs/backend/audit/spec.md | 40 +++++++++++++++++ openspec/specs/backend/auth/spec.md | 44 +++++++++++++++++++ openspec/specs/backend/login/spec.md | 25 +++++++++++ openspec/specs/backend/res/spec.md | 32 ++++++++++++++ sources/sysmgr-nest | 2 +- 13 files changed, 142 insertions(+), 1 deletion(-) rename openspec/changes/{close-phase-0 => archive/2026-10-10-close-phase-0}/.openspec.yaml (100%) rename openspec/changes/{close-phase-0 => archive/2026-10-10-close-phase-0}/design.md (100%) rename openspec/changes/{close-phase-0 => archive/2026-10-10-close-phase-0}/proposal.md (100%) rename openspec/changes/{close-phase-0 => archive/2026-10-10-close-phase-0}/specs/backend/audit/spec.md (100%) rename openspec/changes/{close-phase-0 => archive/2026-10-10-close-phase-0}/specs/backend/auth/spec.md (100%) rename openspec/changes/{close-phase-0 => archive/2026-10-10-close-phase-0}/specs/backend/login/spec.md (100%) rename openspec/changes/{close-phase-0 => archive/2026-10-10-close-phase-0}/specs/backend/res/spec.md (100%) rename openspec/changes/{close-phase-0 => archive/2026-10-10-close-phase-0}/tasks.md (100%) create mode 100644 openspec/specs/backend/audit/spec.md create mode 100644 openspec/specs/backend/auth/spec.md create mode 100644 openspec/specs/backend/login/spec.md create mode 100644 openspec/specs/backend/res/spec.md diff --git a/openspec/changes/close-phase-0/.openspec.yaml b/openspec/changes/archive/2026-10-10-close-phase-0/.openspec.yaml similarity index 100% rename from openspec/changes/close-phase-0/.openspec.yaml rename to openspec/changes/archive/2026-10-10-close-phase-0/.openspec.yaml diff --git a/openspec/changes/close-phase-0/design.md b/openspec/changes/archive/2026-10-10-close-phase-0/design.md similarity index 100% rename from openspec/changes/close-phase-0/design.md rename to openspec/changes/archive/2026-10-10-close-phase-0/design.md diff --git a/openspec/changes/close-phase-0/proposal.md b/openspec/changes/archive/2026-10-10-close-phase-0/proposal.md similarity index 100% rename from openspec/changes/close-phase-0/proposal.md rename to openspec/changes/archive/2026-10-10-close-phase-0/proposal.md diff --git a/openspec/changes/close-phase-0/specs/backend/audit/spec.md b/openspec/changes/archive/2026-10-10-close-phase-0/specs/backend/audit/spec.md similarity index 100% rename from openspec/changes/close-phase-0/specs/backend/audit/spec.md rename to openspec/changes/archive/2026-10-10-close-phase-0/specs/backend/audit/spec.md diff --git a/openspec/changes/close-phase-0/specs/backend/auth/spec.md b/openspec/changes/archive/2026-10-10-close-phase-0/specs/backend/auth/spec.md similarity index 100% rename from openspec/changes/close-phase-0/specs/backend/auth/spec.md rename to openspec/changes/archive/2026-10-10-close-phase-0/specs/backend/auth/spec.md diff --git a/openspec/changes/close-phase-0/specs/backend/login/spec.md b/openspec/changes/archive/2026-10-10-close-phase-0/specs/backend/login/spec.md similarity index 100% rename from openspec/changes/close-phase-0/specs/backend/login/spec.md rename to openspec/changes/archive/2026-10-10-close-phase-0/specs/backend/login/spec.md diff --git a/openspec/changes/close-phase-0/specs/backend/res/spec.md b/openspec/changes/archive/2026-10-10-close-phase-0/specs/backend/res/spec.md similarity index 100% rename from openspec/changes/close-phase-0/specs/backend/res/spec.md rename to openspec/changes/archive/2026-10-10-close-phase-0/specs/backend/res/spec.md diff --git a/openspec/changes/close-phase-0/tasks.md b/openspec/changes/archive/2026-10-10-close-phase-0/tasks.md similarity index 100% rename from openspec/changes/close-phase-0/tasks.md rename to openspec/changes/archive/2026-10-10-close-phase-0/tasks.md diff --git a/openspec/specs/backend/audit/spec.md b/openspec/specs/backend/audit/spec.md new file mode 100644 index 0000000..fb57142 --- /dev/null +++ b/openspec/specs/backend/audit/spec.md @@ -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** 系统记录告警日志,业务请求照常返回成功结果 diff --git a/openspec/specs/backend/auth/spec.md b/openspec/specs/backend/auth/spec.md new file mode 100644 index 0000000..dd2d886 --- /dev/null +++ b/openspec/specs/backend/auth/spec.md @@ -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 部门过滤,返回全量数据 diff --git a/openspec/specs/backend/login/spec.md b/openspec/specs/backend/login/spec.md new file mode 100644 index 0000000..ac2f496 --- /dev/null +++ b/openspec/specs/backend/login/spec.md @@ -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 说明账号状态原因 diff --git a/openspec/specs/backend/res/spec.md b/openspec/specs/backend/res/spec.md new file mode 100644 index 0000000..412c0dc --- /dev/null +++ b/openspec/specs/backend/res/spec.md @@ -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 不进入接口权限集(菜单用于导航渲染,不用于接口鉴权) diff --git a/sources/sysmgr-nest b/sources/sysmgr-nest index 7340658..ce2aa35 160000 --- a/sources/sysmgr-nest +++ b/sources/sysmgr-nest @@ -1 +1 @@ -Subproject commit 7340658305de30b234bc87e0b5490e4c34a49b9a +Subproject commit ce2aa35a24ab351433ae7bb98aba2cab38c7e676