角色管理与权限矩阵方案.md 5.4 KB

角色管理与权限矩阵方案

需求来源:prompts.md(用户管理模块增加角色管理) 状态:已确认(2026-08-20);2026-08-31 修订:移除"可访问部门"维度(见文末修订记录)

需求重申

在用户管理模块中新增角色管理:

  1. 角色 CRUD:新建/编辑/删除角色;可设置(或取消)一个默认角色——未选择角色的用户自动套用默认角色权限
  2. 角色关联用户:角色可关联多个用户;用户编辑时可单选角色
  3. 表格式权限矩阵:
    • 横向表头(操作列,7 项):查看 / 下载 / 编辑 / 删除 / 授权 / 挂载附件 / 解除挂载(与 AllowedAction 对齐)
    • 纵向表头(两级):第一级 = 五个密级(公开/内部/秘密/机密/绝密),第二级 = 所属部门方案 / 其他部门方案 → 共 5×2 = 10 行
    • 表头复选框:每个行头与每个列头均有复选框,勾选/取消即批量切换整行或整列
  4. 权限叠加:矩阵与现有单文档 ACL 为 OR 叠加(矩阵为主权限源;现有 ACL 保留,后续将演进为限时跨部门借阅,本次不实现限时)

关键设计决策(已确认)

决策点 结论
ADMIN 与自定义角色关系 保留内置超管:role_code(ADMIN/USER)不变,ADMIN 恒为超管(绕过矩阵,密级限制仍适用);自定义角色仅挂 USER 体系
矩阵与文档 ACL 关系 OR 叠加;后续 ACL 迁移为限时借阅权限(本次不实现)
部门两分类判定 所属部门 = 文档归属机构是用户机构或其下级(org_path 前缀);其余(含文档无归属)= 其他部门

数据模型(迁移 0012_role_management,0021 修订)

表 结构
sys_role id、role_name、sort_no、status(ENABLED/DISABLED)、remark、is_default、default_marker(计算列:is_default=1→1 否则 NULL)+ 唯一约束保证全局至多一个默认角色(复用 active_marker 模式)+ BusinessTableMixin
sys_role_permission role_id、security_level、dept_scope(OWN/OTHER)、can_view / can_download / can_edit / can_delete / can_config_permission / can_bind_attachment / can_unbind_attachment(布尔列,每角色固定 10 行)+ 唯一约束 (role_id, security_level, dept_scope, active_marker) + BusinessTableMixin
sys_user 新增 role_id FK → sys_role 可空(NULL → 默认角色)

权限判定融合(authorization_service.py)

evaluate_plan_access / plan_allowed_actions 新增矩阵判定:

  1. 密级前置检查不变(密级不足一律拒绝,ADMIN 也不绕过)
  2. 部门归属分类:文档 org_path 以用户机构 org_path 为前缀 → OWN;否则(含文档无归属)→ OTHER
  3. 取用户角色(无 → 默认角色;无默认 → 矩阵贡献为空)→ 查 (security_level, dept_scope) 行 → 与 ACL 结果 OR 叠加
  4. 角色矩阵变更不动 auth_version(权限实时查库);用户换角色时 auth_version+1

API 设计

  • 全部 admin_required + business_audit 审计
  • 新 AuditAction:CREATE_ROLE / EDIT_ROLE / DELETE_ROLE / CHANGE_ROLE_PERMISSION / CHANGE_ROLE_USER;AuditTarget.ROLE
  • 新错误:RoleInUseError(ROLE_IN_USE)、RoleNotFound、默认角色/矩阵参数校验错误

前端(DirectoryPage)

  1. 第三个 Tab "角色管理":角色列表(名称/默认/成员数/状态/操作)
  2. 角色编辑弹窗:名称、排序、状态、是否默认
  3. 角色详情:基本信息 + 权限矩阵表格(行头两级嵌套,行头/列头复选框全选切换)
  4. UserEditorModal 增加"角色"下拉(仅 USER 显示)

实现阶段

接口 说明
GET /roles(分页+keyword+status) 角色列表(含成员数、isDefault)
POST /roles 新建(roleName/sortNo/status/remark/isDefault)
PUT /roles/ 编辑(rowVersion 乐观锁)
DELETE /roles/?rowVersion= 删除(有关联用户时拒绝,ROLE_IN_USE)
GET /roles//permissions 10×7 矩阵
PUT /roles//permissions 矩阵整存整取(rowVersion)
PUT /roles//users 关联用户集合(rowVersion)
GET /users 扩展 User DTO 增加 roleId/roleName
阶段 内容 验证
1 数据模型 + 迁移 0012 test_migration.py
2 角色 CRUD/矩阵/用户关联 API + 审计 + OpenAPI 新增 pytest
3 authorization_service 矩阵判定融合 判定单测 + 既有 90 测试守底
4 前端角色 Tab + 矩阵 + 用户角色下拉 tsc + vitest
5 全量回归 前后端全量测试

风险

  • 高:evaluate_plan_access 为核心访问路径,融合必须零回归(既有测试守底)
  • 中:默认角色唯一性并发(default_marker 计算列 + 唯一约束 DB 层兜底)
  • 中:矩阵整存整取与乐观锁交互
  • 低:文档 organization_id 为空的历史数据 → 归入 OTHER

修订记录

  • 2026-08-31(迁移 0021 / Flyway V6):移除"可访问部门"维度——sys_role_dept 表删除、GET/PUT /roles/<id>/departments 接口下线、DeptScope 收敛为 OWN/OTHER(OTHER 涵盖所属部门子树外全部部门,含无归属文档)、矩阵由 15 行收敛为 10 行、存量 ASSIGNED 权限行物理删除、UI 字典 deptScopes 同步收敛。原"已配置部门"语义取消,跨部门访问由"其他部门"行承载。