From d77c6425bc514ab82f07dd2872c4f263a8144201 Mon Sep 17 00:00:00 2001 From: weichen Date: Wed, 14 Oct 2026 16:37:01 +0000 Subject: [PATCH] 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 --- ...-10-15-iam-focused-role-permission-spec.md | 133 ++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 docs/proposals/2026-10-15-iam-focused-role-permission-spec.md diff --git a/docs/proposals/2026-10-15-iam-focused-role-permission-spec.md b/docs/proposals/2026-10-15-iam-focused-role-permission-spec.md new file mode 100644 index 0000000..0f13819 --- /dev/null +++ b/docs/proposals/2026-10-15-iam-focused-role-permission-spec.md @@ -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 权限、工作流重建、新的文档审签流程、生产迁移或部署。现有文档三权只接入新的角色资格和项目权限判定。