You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

2.4 KiB

ADR-0018: 数据权限按业务模块可配

Date: 2026-08-11
Status: Accepted

Context

原数据权限机制为「单一全局档位」:SysRole.dataScope 存一个 1-4 的整数,对用户所有受控表统一应用。这意味着一个角色对客户模块和线索模块只能有相同的可见范围(如全部可见或仅本人),无法满足「销售对客户看全部、对线索看本部门」这类差异化需求。

Decision

将数据权限从「单一全局档位」改造为「按业务模块分别配置档位」:

  1. 模块注册表 — 新增 sys_data_scope_module 表(code/name/sort/status/builtin),数据驱动,管理员可 CRUD。
  2. 角色×模块档位 — 新增 sys_role_data_scope(role_id, module_code, data_scope) 表,一个角色对每个模块各有一档。删除 SysRole.dataScope 列。
  3. 注解声明@DataScope 注解新增必填 module 属性,引用注册表 code。启动时 PermissionConfig 校验 code 在注册表中存在,不存在则拒绝启动。
  4. 上下文值对象DataVisibility 持有 Map<String, DataScopeLevel> 替代单个 level;DataVisibilityContext.currentScope(moduleCode) 加参数取该模块的 scope。
  5. 拦截器顺序调换 — 先解析 SQL 找表 → 查注解(含 module)→ 用 anno.module() 从上下文取该模块的 scope → 注入 WHERE。
  6. 解析器每模块取最宽PermissionResolverImplsys_role_data_scopemodule_code 分组,每组取最宽 level(ADR-0008 规则下沉到每模块)。未配模块默认 SELF(最窄档,fail safe)。
  7. 删除 CUSTOM(5)DataScopeEnum.CUSTOM 从枚举中移除。
  8. API 契约RoleController.saveOrUpdatemoduleScopes JSON 字符串表单字段替代 dataScope;新增 GET /api/data-scope/modules 列出可用模块。
  9. 迁移策略 — 一次性 SQL 脚本(单事务,CROSS JOIN 旧值,DROP 旧列)。

Consequences

  • 角色配置从「选一个档位」变为「每模块各选一档」,前端角色编辑页需要改造。
  • DataVisibility API 破坏性变更:visibilityScope()visibilityScope(String moduleCode),所有调用方需加参数。
  • 写侧不受影响:currentOwnership() 是身份维度(userId/deptId),与档位正交。
  • 迁移脚本将旧 sys_role.data_scope 值通过 CROSS JOIN 展开到所有注册模块,保留原有行为。