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
2.4 KiB
ADR-0018: 数据权限按业务模块可配
Date: 2026-08-11
Status: Accepted
Context
原数据权限机制为「单一全局档位」:SysRole.dataScope 存一个 1-4 的整数,对用户所有受控表统一应用。这意味着一个角色对客户模块和线索模块只能有相同的可见范围(如全部可见或仅本人),无法满足「销售对客户看全部、对线索看本部门」这类差异化需求。
Decision
将数据权限从「单一全局档位」改造为「按业务模块分别配置档位」:
- 模块注册表 — 新增
sys_data_scope_module表(code/name/sort/status/builtin),数据驱动,管理员可 CRUD。 - 角色×模块档位 — 新增
sys_role_data_scope(role_id, module_code, data_scope)表,一个角色对每个模块各有一档。删除SysRole.dataScope列。 - 注解声明 —
@DataScope注解新增必填module属性,引用注册表 code。启动时PermissionConfig校验 code 在注册表中存在,不存在则拒绝启动。 - 上下文值对象 —
DataVisibility持有Map<String, DataScopeLevel>替代单个 level;DataVisibilityContext.currentScope(moduleCode)加参数取该模块的 scope。 - 拦截器顺序调换 — 先解析 SQL 找表 → 查注解(含 module)→ 用
anno.module()从上下文取该模块的 scope → 注入 WHERE。 - 解析器每模块取最宽 —
PermissionResolverImpl查sys_role_data_scope按module_code分组,每组取最宽 level(ADR-0008 规则下沉到每模块)。未配模块默认 SELF(最窄档,fail safe)。 - 删除 CUSTOM(5) —
DataScopeEnum.CUSTOM从枚举中移除。 - API 契约 —
RoleController.saveOrUpdate用moduleScopesJSON 字符串表单字段替代dataScope;新增GET /api/data-scope/modules列出可用模块。 - 迁移策略 — 一次性 SQL 脚本(单事务,CROSS JOIN 旧值,DROP 旧列)。
Consequences
- 角色配置从「选一个档位」变为「每模块各选一档」,前端角色编辑页需要改造。
DataVisibilityAPI 破坏性变更:visibilityScope()→visibilityScope(String moduleCode),所有调用方需加参数。- 写侧不受影响:
currentOwnership()是身份维度(userId/deptId),与档位正交。 - 迁移脚本将旧
sys_role.data_scope值通过 CROSS JOIN 展开到所有注册模块,保留原有行为。