# 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` 4. 部门集合 / 子树展开只算一次——**任一**模块的 widest 是 DEPT_AND_CHILDREN 就算 expandedDeptIds 5. 建一份 `DataVisibility(userId, primaryDeptId, deptIds, moduleLevels, expandedDeptIds)` ```java // 新增依赖:SysRoleDataScopeMapper(02 建的 mapper) List roleScopes = sysRoleDataScopeMapper.selectList( new LambdaQueryWrapper().in(SysRoleDataScope::getRoleId, roleIds)); Map 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` 的前半部分),后半段不动。