Define the focused role and permission system
Why: The implementation scope must match the requested single-role position model and three permission layers without carrying unrelated IAM work. Evidence: The spec was checked for placeholders, internal contradictions, and whitespace errors. Impact: Backend becomes the role authority while RDM retains project permissions and document duties. Refs: IAM role and permission system
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
---
|
||||
title: 聚焦版角色与分层权限系统规格
|
||||
date: 2026-10-15
|
||||
type: feature
|
||||
status: review
|
||||
supersedes_scope: 2026-10-13-identity-role-permission-plan.md U4-U7 中超出本文的部分
|
||||
---
|
||||
|
||||
# 聚焦版角色与分层权限系统规格
|
||||
|
||||
## 目标
|
||||
|
||||
实现用户要求的角色与权限系统,不引入账号恢复、多职位、Agent 授权或新的工作流能力。
|
||||
|
||||
首期角色等同企业职位。角色与用户分离:同一角色可分配给多个用户,每个用户同时只有一个生效角色。角色包含稳定 `roleId`、名称、可选描述、启用状态和版本。用户继续使用稳定 `userId`,姓名、电话、邮箱、工号、部门和备注均为可选资料,不参与授权主键。
|
||||
|
||||
权限分为三个配置面,但使用同一服务端动作目录和判定结果:
|
||||
|
||||
1. 系统权限控制系统设置、账号管理、角色管理、权限上限和项目创建。
|
||||
2. 角色权限描述一个职位默认可以执行的动作及其上限,例如创建项目、查看获准目录信息。
|
||||
3. 项目权限只在一个项目内生效,由该项目创建者维护;A 项目的管理权不能用于 B 项目。
|
||||
|
||||
系统管理员负责账号、角色和平台权限上限。系统管理员没有他人项目业务内容的隐式访问权,读取项目正文、原件、草稿、业务审计或导出仍需该项目的明确授权。
|
||||
|
||||
## 范围
|
||||
|
||||
### 角色与用户
|
||||
|
||||
- `Role`:`roleId`、名称、描述、状态、`roleVersion`、创建者、修改者和时间。
|
||||
- `UserRoleBinding`:`bindingId`、`userId`、`roleId`、状态、版本、任命者和任命时间。
|
||||
- 一个用户最多一条有效 binding;同一角色允许任意多个有效用户 binding。
|
||||
- 改名、编辑描述和停用角色不改变用户、项目或历史记录的稳定 ID。
|
||||
- 停用角色时保留 binding 和审计记录,但其角色授权立即失效;不回落到更宽的默认权限。
|
||||
- 任命停用角色、未知角色或停用账号均拒绝。
|
||||
|
||||
### 权限目录与三层授权
|
||||
|
||||
动作目录由受信注册表定义 `actionId`、中文名、说明、scope、分组、风险级别和是否受保护。请求不能通过动作字符串或请求体自行声明 scope。
|
||||
|
||||
首期系统动作至少包括:
|
||||
|
||||
| 分组 | 动作 |
|
||||
|---|---|
|
||||
| 系统设置 | `system.settings.read`、`system.settings.write` |
|
||||
| 用户管理 | `system.users.view`、`system.users.create`、`system.users.edit`、`system.users.disable` |
|
||||
| 角色管理 | `system.roles.view`、`system.roles.manage`、`system.roles.assign` |
|
||||
| 权限管理 | `system.permissions.view`、`system.permissions.manage` |
|
||||
| 项目入口 | `project.create` |
|
||||
|
||||
受保护的角色、权限和管理员管理动作只能来自明确系统授权,普通角色配置不能授予。`project.create` 可以来自明确系统授权或当前有效角色的允许项,但仍受平台上限约束。
|
||||
|
||||
项目动作至少包括 `project.settings`、`project.members.manage`、`project.permissions.manage`、`document.duties.assign`、`document.read`、`document.author`、`document.review`、`document.approve`。项目动作必须同时满足:账号有效、项目关系有效、当前角色有效、角色动作允许且未超过角色上限、平台未禁止、项目未明确拒绝、资源关系和文档状态允许。
|
||||
|
||||
项目创建者只获得自己项目的管理默认,且仍受平台和角色上限约束。创建者关系不授予其他项目权限,也不自动授予项目业务内容读取或代签能力。
|
||||
|
||||
### 角色权限
|
||||
|
||||
每个角色的动作配置包含 `allowed` 与 `capAllowed`:
|
||||
|
||||
- `allowed=true` 表示该角色默认允许动作。
|
||||
- `capAllowed=false` 表示该角色不能通过项目覆盖获得该动作。
|
||||
- `allowed=true && capAllowed=false` 是非法配置,服务端拒绝。
|
||||
- 未知动作和未配置动作默认拒绝。
|
||||
- 角色默认和上限不得写入超出操作者可委派范围的受保护动作。
|
||||
|
||||
首期一个用户只有一个有效角色,因此一次判定只使用该 binding,不进行跨角色动作或范围拼接。
|
||||
|
||||
### 项目权限和文档三权
|
||||
|
||||
RDM 保留项目成员、项目创建者、项目内覆盖和现有文档三权的领域权威。Backend 负责角色、binding、系统动作和平台/角色上限。
|
||||
|
||||
项目覆盖使用 `inherit | allow | deny`:`allow` 不能突破平台或角色上限,`deny` 明确阻断。项目创建者只能修改自己创建项目的成员、权限和文档三权。
|
||||
|
||||
文档编制、审核、批准继续使用现有 RDM 三权记录;分配候选必须是该项目有效成员,账号和角色有效,并具有对应动作上限。角色只提供资格,不能代替具体文档职责。
|
||||
|
||||
## 服务端接口
|
||||
|
||||
Backend 成为角色和系统权限的唯一写入权威,提供版本化接口:
|
||||
|
||||
- `GET /api/admin/permissions/catalog`
|
||||
- `GET /api/admin/roles`,支持名称精确/模糊搜索、状态和动作过滤、分页
|
||||
- `POST /api/admin/roles`
|
||||
- `GET /api/admin/roles/{roleId}`
|
||||
- `PATCH /api/admin/roles/{roleId}`,使用 `expectedRoleVersion`
|
||||
- `PUT /api/admin/roles/{roleId}/permissions`,批量提交固定 actionId 列表和 `expectedRoleVersion`
|
||||
- `PUT /api/admin/users/{userId}/role`,替换该用户唯一有效角色,使用用户状态版本和幂等键
|
||||
- `GET /api/admin/users/{userId}/role`
|
||||
- `GET /api/authz/explain`,仅解释调用者自己或其有权管理的对象
|
||||
|
||||
批量权限修改在单库事务内全部成功或全部失败;任一未知动作、越权、越上限或版本冲突不得部分写入。响应返回新版本、实际差异和审计回执标识。
|
||||
|
||||
RDM 通过公开、固定版本的 Backend 角色读取/判定契约消费角色数据。RDM 原 `rdm.role.*` 写命令在迁移期转发 Backend;切换完成后不得继续写 RDM 旧角色表。读取失败、提供者缺失或版本不兼容时拒绝权限动作。
|
||||
|
||||
## 配置界面
|
||||
|
||||
系统管理区增加“角色与权限”入口:
|
||||
|
||||
- 角色列表显示名称、描述、状态和绑定人数,支持精确搜索、模糊搜索和状态过滤。
|
||||
- 单角色视图编辑名称、描述、状态及权限。
|
||||
- 角色矩阵以角色为行、权限为列,按权限分组和分页展示。
|
||||
- 单角色视图与矩阵使用同一草稿模型和同一批量接口。
|
||||
- 过滤隐藏的单元格不丢失草稿;全选只作用于当前明确显示的固定 actionId 集合。
|
||||
- 提交前显示差异;冲突保留草稿并要求刷新,不逐格即时写库。
|
||||
|
||||
用户详情显示当前角色,并允许有 `system.roles.assign` 权限的操作者从有效角色中选择。用户可选资料继续用于展示、搜索和辨识,不参与权限计算。
|
||||
|
||||
项目设置继续使用现有成员和权限入口,显示角色默认、角色上限、项目覆盖及最终允许/拒绝原因。项目创建者无法切换到其他项目后沿用原项目管理权。
|
||||
|
||||
## 迁移与兼容
|
||||
|
||||
1. 导出 RDM 当前角色、动作配置和账号单角色绑定,包含来源版本与摘要。
|
||||
2. 以原 `roleId` 导入 Backend;为每个账号生成一个稳定 binding。
|
||||
3. 对角色数量、绑定数量、动作默认/上限和引用逐项比对。
|
||||
4. 在迁移窗口内禁止双主写;RDM 写入口改为转发 Backend。
|
||||
5. 切换消费者后保留旧表只读,确认无回退依赖后再另行批准清理。
|
||||
|
||||
迁移失败不得启用部分角色数据;恢复时保留已撤销、停用和拒绝事实,不能复活旧权限。
|
||||
|
||||
## 验收条件
|
||||
|
||||
- 创建“软件工程师”角色并分配给两个用户,两人保留各自稳定 userId。
|
||||
- 同一用户第二次任命替换原生效角色,不产生两个同时有效的 binding。
|
||||
- 角色描述可编辑,用户可选资料全空仍合法。
|
||||
- 未知动作、默认超过上限、停用角色任命、无授权角色管理和最后系统权限管理者撤销均拒绝。
|
||||
- 普通角色可被授予 `project.create`,但不能因此修改系统设置、用户、角色或权限上限。
|
||||
- A 项目创建者管理 A 的成员、项目权限和文档三权成功;操作 B 全部拒绝。
|
||||
- 系统管理员未获项目授权时不能读取 A 或 B 的业务内容。
|
||||
- 单角色配置和角色矩阵产生等价的固定 actionId 批量 patch;过滤和分页不丢草稿。
|
||||
- SQLite 与 PostgreSQL 的版本冲突、事务回滚和迁移结果一致。
|
||||
|
||||
## 明确排除
|
||||
|
||||
本增量不实现一人多职、账号恢复、SSO/组织树、Agent 权限、工作流重建、新的文档审签流程、生产迁移或部署。现有文档三权只接入新的角色资格和项目权限判定。
|
||||
Reference in New Issue
Block a user