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.
80 lines
3.8 KiB
80 lines
3.8 KiB
|
4 weeks ago
|
# 05 · 拦截器按模块取档:DataScopeInterceptor / PermissionResolverImpl
|
||
|
|
|
||
|
|
Type: grilling
|
||
|
|
Status: resolved
|
||
|
|
Blocked by: 01, 04
|
||
|
|
|
||
|
|
## Question
|
||
|
|
|
||
|
|
`DataScopeInterceptor` 拦到某张受控表时,如何知道它属于哪个模块、取该模块的 scope?
|
||
|
|
`PermissionResolverImpl.resolve` 如何算出「每模块各自取最宽」的一组档位?
|
||
|
|
|
||
|
|
要定的点:
|
||
|
|
|
||
|
|
- 拦截器:拦到表 → 查表所属模块(依赖 01 的表→模块映射)→ 从上下文取该模块 scope → 注入 WHERE。
|
||
|
|
表不属任何模块时的行为(依赖 01 对「未接入表」的裁决)。
|
||
|
|
- `PermissionResolverImpl.resolve`:现在遍历角色取全局最宽;改成对每个模块分别在所有角色的
|
||
|
|
该模块档位里取最宽,结出一组 DataVisibility(依赖 02 存储、04 上下文形态)。
|
||
|
|
- 部门集合/子树展开只算一次、各模块档位复用(承接 04 的结论)。
|
||
|
|
- 权限码并集、可见菜单树等 `resolve` 的其他产物**不受影响**,只动数据可见性那段。
|
||
|
|
|
||
|
|
依赖 01(表→模块映射)与 04(上下文/值对象形态)。
|
||
|
|
|
||
|
|
## Answer
|
||
|
|
|
||
|
|
全部从 01 和 04 推导,无新决策。
|
||
|
|
|
||
|
|
### 1. 拦截器 DataScopeInterceptor:顺序调换
|
||
|
|
|
||
|
|
**现在**:先拿一份 scope → 如果 ALL_VISIBLE 跳过 → 解析 SQL 找表 → 查注解 → 造 WHERE。
|
||
|
|
|
||
|
|
**改成**:解析 SQL 找表 → 查注解(含 01 加的 `module` 属性)→ 用 `anno.module()` 取该模块的 scope `currentScope(anno.module())` → 如果 ALL_VISIBLE 跳过这张表 → 造 WHERE。
|
||
|
|
|
||
|
|
```java
|
||
|
|
// 现在 line 52
|
||
|
|
VisibilityScope scope = DataVisibilityContext.currentScope();
|
||
|
|
if (scope.kind() == ALL_VISIBLE) return invocation.proceed();
|
||
|
|
// ... 后面找表、查注解
|
||
|
|
|
||
|
|
// 改成:先找表、查注解,再取 scope
|
||
|
|
DataScope anno = tables.find(tableName);
|
||
|
|
if (anno == null) return select.toString();
|
||
|
|
VisibilityScope scope = DataVisibilityContext.currentScope(anno.module());
|
||
|
|
if (scope.kind() == ALL_VISIBLE) return select.toString();
|
||
|
|
Expression condition = buildCondition(scope, anno);
|
||
|
|
```
|
||
|
|
|
||
|
|
- 全局 ALL_VISIBLE 早退优化取消——不同模块档位不同,不能在解析 SQL 前判断。
|
||
|
|
- `DataScopeTables` 不需改——它存的是 `@DataScope` 注解实例,注解加了 `module` 后自动带出。
|
||
|
|
- `buildCondition` 不变——它只看 `VisibilityScope` 的 kind/ownerId/deptIds + 注解的 ownerColumn/deptColumn。
|
||
|
|
|
||
|
|
### 2. 解析器 PermissionResolverImpl.resolve:每模块各取最宽
|
||
|
|
|
||
|
|
**现在**:遍历角色 → 取全局最宽 level → 建一份 DataVisibility。
|
||
|
|
|
||
|
|
**改成**:
|
||
|
|
1. 查 `sys_role_data_scope`(02 新表)中该用户所有角色的行
|
||
|
|
2. 按 module_code 分组,每组取最宽 level(角色无行 = 贡献 SELF,02 决策 3)
|
||
|
|
3. 组成 `Map<String, DataScopeLevel>`
|
||
|
|
4. 部门集合 / 子树展开只算一次——**任一**模块的 widest 是 DEPT_AND_CHILDREN 就算 expandedDeptIds
|
||
|
|
5. 建一份 `DataVisibility(userId, primaryDeptId, deptIds, moduleLevels, expandedDeptIds)`
|
||
|
|
|
||
|
|
```java
|
||
|
|
// 新增依赖:SysRoleDataScopeMapper(02 建的 mapper)
|
||
|
|
List<SysRoleDataScope> roleScopes = sysRoleDataScopeMapper.selectList(
|
||
|
|
new LambdaQueryWrapper<SysRoleDataScope>().in(SysRoleDataScope::getRoleId, roleIds));
|
||
|
|
Map<String, DataScopeLevel> moduleLevels = new HashMap<>();
|
||
|
|
for (SysRoleDataScope rs : roleScopes) {
|
||
|
|
DataScopeLevel level = DataScopeLevel.fromCode(rs.getDataScope());
|
||
|
|
moduleLevels.merge(rs.getModuleCode(), level,
|
||
|
|
(a, b) -> a.getCode() >= b.getCode() ? a : b);
|
||
|
|
}
|
||
|
|
// 无行的模块不进 map,DataVisibility.visibilityScope() 用 getOrDefault(moduleCode, SELF)
|
||
|
|
```
|
||
|
|
|
||
|
|
- `expandedDeptIds` 判定从 `widest == DEPT_AND_CHILDREN` 改为 `moduleLevels.values().stream().anyMatch(l -> l == DEPT_AND_CHILDREN)`
|
||
|
|
|
||
|
|
### 3. 不受影响
|
||
|
|
|
||
|
|
权限码并集、可见菜单树、角色编码——只动数据可见性那段(`resolve` 的前半部分),后半段不动。
|