# 数据权限控制 **本文引用的文件** - [DataScope.java](file://crm-base/src/main/java/com/crm/base/annotation/DataScope.java) - [DataScopeLevel.java](file://crm-base/src/main/java/com/crm/base/security/DataScopeLevel.java) - [DataScopeHelper.java](file://crm-base/src/main/java/com/crm/base/security/DataScopeHelper.java) - [DataVisibilityContext.java](file://crm-base/src/main/java/com/crm/base/security/DataVisibilityContext.java) - [LoginUser.java](file://crm-base/src/main/java/com/crm/base/security/LoginUser.java) - [SecurityUtils.java](file://crm-base/src/main/java/com/crm/base/security/SecurityUtils.java) - [CrmSqlInjector.java](file://crm-base/src/main/java/com/crm/base/config/CrmSqlInjector.java) - [MybatisPlusConfig.java](file://crm-base/src/main/java/com/crm/base/config/MybatisPlusConfig.java) - [DataScopeInterceptor.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeInterceptor.java) - [DataScopeTables.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeTables.java) - [DataScopeEnum.java](file://crm-auth/src/main/java/com/crm/auth/domain/enums/DataScopeEnum.java) - [SysDeptMapper.java](file://crm-auth/src/main/java/com/crm/auth/mapper/SysDeptMapper.java) - [SysDeptServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysDeptServiceImpl.java) - [AuthUserMapper.java](file://crm-auth/src/main/java/com/crm/auth/mapper/AuthUserMapper.java) - [AuthServiceImp.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/AuthServiceImpl.java) - [DataScopeIntegrationTest.java](file://crm-auth/src/test/java/com/crm/auth/security/scope/DataScopeIntegrationTest.java) - [TestOwnedData.java](file://crm-auth/src/test/java/com/crm/auth/security/scope/TestOwnedData.java) - [TestOwnedDataMapper.java](file://crm-auth/src/test/java/com/crm/auth/security/scope/TestOwnedDataMapper.java) ## 目录 1. [简介](#简介) 2. [项目结构](#项目结构) 3. [核心组件](#核心组件) 4. [架构总览](#架构总览) 5. [详细组件分析](#详细组件分析) 6. [依赖关系分析](#依赖关系分析) 7. [性能考虑](#性能考虑) 8. [故障排查指南](#故障排查指南) 9. [结论](#结论) 10. [附录:配置与使用示例](#附录配置与使用示例) ## 简介 本文件面向CRM系统的数据权限控制,围绕DataScope注解、DataScopeHelper工具类、DataScopeTables自动注入机制以及MyBatis拦截器DataScopeInterceptor展开,系统性阐述“全部数据、本部门数据、本部门及以下数据、仅本人数据”四类数据范围级别的实现原理、动态SQL生成策略、拦截器工作流与性能优化建议。文档同时提供常见使用场景的配置与调用示例路径,帮助开发者快速落地数据权限能力。 ## 项目结构 数据权限相关代码分布在基础模块与认证模块中: - 基础模块(crm-base):定义数据权限注解、上下文、工具类、MyBatis Plus扩展(SQL注入器)。 - 认证模块(crm-auth):实现数据权限拦截器、表级元数据注册、枚举定义以及与部门/用户相关的查询服务。 ```mermaid graph TB subgraph "基础模块 crm-base" A["注解 DataScope"] B["级别 DataScopeLevel"] C["工具 DataScopeHelper"] D["上下文 DataVisibilityContext"] E["登录用户 LoginUser"] F["安全工具 SecurityUtils"] G["SQL注入器 CrmSqlInjector"] H["MyBatis配置 MybatisPlusConfig"] end subgraph "认证模块 crm-auth" I["拦截器 DataScopeInterceptor"] J["表元数据 DataScopeTables"] K["枚举 DataScopeEnum"] L["部门服务 SysDeptServiceImpl"] M["部门映射 SysDeptMapper"] N["用户映射 AuthUserMapper"] O["认证服务 AuthServiceImpl"] P["集成测试 DataScopeIntegrationTest"] end A --> C B --> C C --> D D --> E F --> D G --> H I --> J I --> C I --> D I --> K L --> M O --> N P --> I ``` **图表来源** - [DataScope.java](file://crm-base/src/main/java/com/crm/base/annotation/DataScope.java) - [DataScopeLevel.java](file://crm-base/src/main/java/com/crm/base/security/DataScopeLevel.java) - [DataScopeHelper.java](file://crm-base/src/main/java/com/crm/base/security/DataScopeHelper.java) - [DataVisibilityContext.java](file://crm-base/src/main/java/com/crm/base/security/DataVisibilityContext.java) - [LoginUser.java](file://crm-base/src/main/java/com/crm/base/security/LoginUser.java) - [SecurityUtils.java](file://crm-base/src/main/java/com/crm/base/security/SecurityUtils.java) - [CrmSqlInjector.java](file://crm-base/src/main/java/com/crm/base/config/CrmSqlInjector.java) - [MybatisPlusConfig.java](file://crm-base/src/main/java/com/crm/base/config/MybatisPlusConfig.java) - [DataScopeInterceptor.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeInterceptor.java) - [DataScopeTables.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeTables.java) - [DataScopeEnum.java](file://crm-auth/src/main/java/com/crm/auth/domain/enums/DataScopeEnum.java) - [SysDeptServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysDeptServiceImpl.java) - [SysDeptMapper.java](file://crm-auth/src/main/java/com/crm/auth/mapper/SysDeptMapper.java) - [AuthUserMapper.java](file://crm-auth/src/main/java/com/crm/auth/mapper/AuthUserMapper.java) - [AuthServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/AuthServiceImpl.java) - [DataScopeIntegrationTest.java](file://crm-auth/src/test/java/com/crm/auth/security/scope/DataScopeIntegrationTest.java) **章节来源** - [DataScope.java](file://crm-base/src/main/java/com/crm/base/annotation/DataScope.java) - [DataScopeLevel.java](file://crm-base/src/main/java/com/crm/base/security/DataScopeLevel.java) - [DataScopeHelper.java](file://crm-base/src/main/java/com/crm/base/security/DataScopeHelper.java) - [DataVisibilityContext.java](file://crm-base/src/main/java/com/crm/base/security/DataVisibilityContext.java) - [LoginUser.java](file://crm-base/src/main/java/com/crm/base/security/LoginUser.java) - [SecurityUtils.java](file://crm-base/src/main/java/com/crm/base/security/SecurityUtils.java) - [CrmSqlInjector.java](file://crm-base/src/main/java/com/crm/base/config/CrmSqlInjector.java) - [MybatisPlusConfig.java](file://crm-base/src/main/java/com/crm/base/config/MybatisPlusConfig.java) - [DataScopeInterceptor.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeInterceptor.java) - [DataScopeTables.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeTables.java) - [DataScopeEnum.java](file://crm-auth/src/main/java/com/crm/auth/domain/enums/DataScopeEnum.java) - [SysDeptServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysDeptServiceImpl.java) - [SysDeptMapper.java](file://crm-auth/src/main/java/com/crm/auth/mapper/SysDeptMapper.java) - [AuthUserMapper.java](file://crm-auth/src/main/java/com/crm/auth/mapper/AuthUserMapper.java) - [AuthServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/AuthServiceImpl.java) - [DataScopeIntegrationTest.java](file://crm-auth/src/test/java/com/crm/auth/security/scope/DataScopeIntegrationTest.java) ## 核心组件 - DataScope注解:用于在接口或方法上声明数据范围级别与目标表字段,驱动后续拦截与SQL改写。 - DataScopeLevel枚举:定义四种数据范围级别(全部数据、本部门数据、本部门及以下数据、仅本人数据)。 - DataScopeHelper:封装数据权限上下文设置、当前用户信息获取、部门树查询等通用逻辑。 - DataVisibilityContext:线程本地上下文,保存当前请求的数据可见性范围与用户信息。 - LoginUser:登录用户模型,包含用户ID、所属部门ID等关键属性。 - SecurityUtils:从安全上下文提取当前登录用户的便捷工具。 - CrmSqlInjector:基于MyBatis Plus的SQL注入器,负责按规则向SQL追加数据权限条件。 - MybatisPlusConfig:注册MyBatis Plus插件与全局配置。 - DataScopeInterceptor:MyBatis拦截器,解析注解、构建并注入数据权限SQL片段。 - DataScopeTables:集中维护需要启用数据权限控制的表及其字段映射。 - DataScopeEnum:数据范围枚举(与级别对应),供拦截器与注入器统一判断。 - 部门/用户服务与映射:为“本部门及以下”等范围提供部门树与用户归属查询支撑。 **章节来源** - [DataScope.java](file://crm-base/src/main/java/com/crm/base/annotation/DataScope.java) - [DataScopeLevel.java](file://crm-base/src/main/java/com/crm/base/security/DataScopeLevel.java) - [DataScopeHelper.java](file://crm-base/src/main/java/com/crm/base/security/DataScopeHelper.java) - [DataVisibilityContext.java](file://crm-base/src/main/java/com/crm/base/security/DataVisibilityContext.java) - [LoginUser.java](file://crm-base/src/main/java/com/crm/base/security/LoginUser.java) - [SecurityUtils.java](file://crm-base/src/main/java/com/crm/base/security/SecurityUtils.java) - [CrmSqlInjector.java](file://crm-base/src/main/java/com/crm/base/config/CrmSqlInjector.java) - [MybatisPlusConfig.java](file://crm-base/src/main/java/com/crm/base/config/MybatisPlusConfig.java) - [DataScopeInterceptor.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeInterceptor.java) - [DataScopeTables.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeTables.java) - [DataScopeEnum.java](file://crm-auth/src/main/java/com/crm/auth/domain/enums/DataScopeEnum.java) - [SysDeptServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysDeptServiceImpl.java) - [SysDeptMapper.java](file://crm-auth/src/main/java/com/crm/auth/mapper/SysDeptMapper.java) - [AuthUserMapper.java](file://crm-auth/src/main/java/com/crm/auth/mapper/AuthUserMapper.java) ## 架构总览 数据权限的整体流程如下: - 控制器层通过注解声明数据范围级别与目标表字段。 - MyBatis拦截器在执行SQL前解析注解与上下文,确定数据范围。 - 根据范围级别与表元数据,动态生成WHERE子句片段(如部门ID IN 子查询、用户ID等于当前用户等)。 - SQL注入器将片段注入到最终执行的SQL中,完成数据过滤。 ```mermaid sequenceDiagram participant Controller as "业务控制器" participant Interceptor as "DataScopeInterceptor" participant Helper as "DataScopeHelper" participant Tables as "DataScopeTables" participant Injector as "CrmSqlInjector" participant DB as "数据库" Controller->>Interceptor : "执行Mapper方法(带@DataScope)" Interceptor->>Helper : "解析注解与上下文" Helper-->>Interceptor : "返回数据范围级别与用户信息" Interceptor->>Tables : "查询目标表字段映射" Tables-->>Interceptor : "返回表字段映射" Interceptor->>Injector : "生成数据权限SQL片段" Injector-->>Interceptor : "返回拼接后的SQL" Interceptor->>DB : "执行最终SQL" DB-->>Controller : "返回受限结果集" ``` **图表来源** - [DataScopeInterceptor.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeInterceptor.java) - [DataScopeHelper.java](file://crm-base/src/main/java/com/crm/base/security/DataScopeHelper.java) - [DataScopeTables.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeTables.java) - [CrmSqlInjector.java](file://crm-base/src/main/java/com/crm/base/config/CrmSqlInjector.java) ## 详细组件分析 ### DataScope注解与级别 - 设计要点 - 注解参数包括数据范围级别与目标表主键/外键字段名,便于拦截器定位需要加条件的列。 - 级别枚举覆盖四种典型场景:全部数据、本部门数据、本部门及以下数据、仅本人数据。 - 使用方式 - 在Service或Controller方法上标注注解,指定级别与字段;若未指定则采用默认策略。 - 级别语义 - 全部数据:不附加任何限制。 - 本部门数据:限定dept_id在当前用户所在部门。 - 本部门及以下数据:限定dept_id在当前用户所在部门及其所有下级部门。 - 仅本人数据:限定owner_id或创建人字段等于当前用户ID。 ```mermaid classDiagram class DataScope { +级别 level +字段 field } class DataScopeLevel { +全部数据 +本部门数据 +本部门及以下数据 +仅本人数据 } DataScope --> DataScopeLevel : "引用" ``` **图表来源** - [DataScope.java](file://crm-base/src/main/java/com/crm/base/annotation/DataScope.java) - [DataScopeLevel.java](file://crm-base/src/main/java/com/crm/base/security/DataScopeLevel.java) **章节来源** - [DataScope.java](file://crm-base/src/main/java/com/crm/base/annotation/DataScope.java) - [DataScopeLevel.java](file://crm-base/src/main/java/com/crm/base/security/DataScopeLevel.java) ### DataScopeHelper工具类 - 职责 - 设置与清理数据可见性上下文(DataVisibilityContext)。 - 获取当前登录用户(LoginUser)及部门信息。 - 提供“本部门及以下”所需的部门树查询入口(通常委托服务层)。 - 关键点 - 线程隔离:通过ThreadLocal保证并发安全。 - 容错处理:当无登录用户或上下文缺失时,降级为最小权限(仅本人或空结果)。 - 缓存优化:对部门树或用户部门信息进行短期缓存,减少重复查询。 ```mermaid flowchart TD Start(["进入方法"]) --> CheckCtx["检查上下文是否存在"] CheckCtx --> |存在| UseCtx["复用上下文中的范围与用户"] CheckCtx --> |不存在| LoadUser["加载当前登录用户"] LoadUser --> LoadDept["加载用户部门信息"] LoadDept --> BuildScope["计算数据范围级别"] BuildScope --> SetCtx["写入上下文"] SetCtx --> End(["结束"]) UseCtx --> End ``` **图表来源** - [DataScopeHelper.java](file://crm-base/src/main/java/com/crm/base/security/DataScopeHelper.java) - [DataVisibilityContext.java](file://crm-base/src/main/java/com/crm/base/security/DataVisibilityContext.java) - [LoginUser.java](file://crm-base/src/main/java/com/crm/base/security/LoginUser.java) - [SecurityUtils.java](file://crm-base/src/main/java/com/crm/base/security/SecurityUtils.java) **章节来源** - [DataScopeHelper.java](file://crm-base/src/main/java/com/crm/base/security/DataScopeHelper.java) - [DataVisibilityContext.java](file://crm-base/src/main/java/com/crm/base/security/DataVisibilityContext.java) - [LoginUser.java](file://crm-base/src/main/java/com/crm/base/security/LoginUser.java) - [SecurityUtils.java](file://crm-base/src/main/java/com/crm/base/security/SecurityUtils.java) ### DataScopeTables表元数据与自动注入 - 设计要点 - 集中维护需要数据权限控制的表名、主键/外键字段映射、是否启用权限开关。 - 支持按表维度开启/关闭权限,避免全量扫描带来的性能损耗。 - 自动注入机制 - 启动时由CrmSqlInjector读取DataScopeTables配置,建立表与字段的映射索引。 - 拦截器在执行SQL前,依据目标表查找映射,决定是否需要注入权限条件。 ```mermaid classDiagram class DataScopeTables { +表名映射 map +字段映射 fieldMap +是否启用 enabled } class CrmSqlInjector { +初始化映射 init() +注入SQL片段 inject() } DataScopeTables <.. CrmSqlInjector : "被读取与使用" ``` **图表来源** - [DataScopeTables.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeTables.java) - [CrmSqlInjector.java](file://crm-base/src/main/java/com/crm/base/config/CrmSqlInjector.java) **章节来源** - [DataScopeTables.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeTables.java) - [CrmSqlInjector.java](file://crm-base/src/main/java/com/crm/base/config/CrmSqlInjector.java) ### DataScopeInterceptor拦截器工作流程 - 触发时机 - MyBatis在执行SQL前拦截StatementHandler,解析@DataScope注解与上下文。 - 核心步骤 - 解析注解:读取级别与字段。 - 获取上下文:从DataVisibilityContext读取当前用户与范围级别。 - 查表映射:从DataScopeTables获取目标表的字段映射。 - 生成片段:根据级别生成WHERE条件片段(部门IN、用户ID相等)。 - 注入SQL:通过CrmSqlInjector将片段拼接到原始SQL。 - 执行SQL:放行至数据库执行。 ```mermaid sequenceDiagram participant MyBatis as "MyBatis" participant Interceptor as "DataScopeInterceptor" participant Helper as "DataScopeHelper" participant Tables as "DataScopeTables" participant Injector as "CrmSqlInjector" MyBatis->>Interceptor : "拦截SQL执行" Interceptor->>Helper : "解析注解与上下文" Helper-->>Interceptor : "返回级别与用户" Interceptor->>Tables : "查询表字段映射" Tables-->>Interceptor : "返回映射" Interceptor->>Injector : "生成并注入SQL片段" Injector-->>Interceptor : "返回新SQL" Interceptor-->>MyBatis : "继续执行SQL" ``` **图表来源** - [DataScopeInterceptor.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeInterceptor.java) - [DataScopeHelper.java](file://crm-base/src/main/java/com/crm/base/security/DataScopeHelper.java) - [DataScopeTables.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeTables.java) - [CrmSqlInjector.java](file://crm-base/src/main/java/com/crm/base/config/CrmSqlInjector.java) **章节来源** - [DataScopeInterceptor.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeInterceptor.java) ### 数据范围级别实现逻辑 - 全部数据 - 不附加任何WHERE条件,直接执行原SQL。 - 本部门数据 - 生成dept_id = 当前用户部门ID的条件。 - 本部门及以下数据 - 先查询当前用户部门的完整子树,生成dept_id IN (子树ID集合)的条件。 - 仅本人数据 - 生成owner_id = 当前用户ID或创建人字段=当前用户ID的条件。 ```mermaid flowchart TD Level["数据范围级别"] --> All["全部数据"] Level --> Dept["本部门数据"] Level --> DeptDown["本部门及以下数据"] Level --> Self["仅本人数据"] All --> NoFilter["不附加条件"] Dept --> FilterDept["dept_id = 当前部门"] DeptDown --> QueryTree["查询部门子树"] QueryTree --> InFilter["dept_id IN (子树ID)"] Self --> FilterOwner["owner_id = 当前用户"] ``` **图表来源** - [DataScopeLevel.java](file://crm-base/src/main/java/com/crm/base/security/DataScopeLevel.java) - [DataScopeEnum.java](file://crm-auth/src/main/java/com/crm/auth/domain/enums/DataScopeEnum.java) - [SysDeptServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysDeptServiceImpl.java) - [SysDeptMapper.java](file://crm-auth/src/main/java/com/crm/auth/mapper/SysDeptMapper.java) - [AuthUserMapper.java](file://crm-auth/src/main/java/com/crm/auth/mapper/AuthUserMapper.java) **章节来源** - [DataScopeLevel.java](file://crm-base/src/main/java/com/crm/base/security/DataScopeLevel.java) - [DataScopeEnum.java](file://crm-auth/src/main/java/com/crm/auth/domain/enums/DataScopeEnum.java) - [SysDeptServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysDeptServiceImpl.java) - [SysDeptMapper.java](file://crm-auth/src/main/java/com/crm/auth/mapper/SysDeptMapper.java) - [AuthUserMapper.java](file://crm-auth/src/main/java/com/crm/auth/mapper/AuthUserMapper.java) ### 动态SQL生成与MyBatis拦截细节 - 动态SQL生成 - 根据级别选择不同条件片段:部门IN、用户ID相等或不附加。 - 字段名来源于DataScopeTables映射,确保与实体字段一致。 - 拦截细节 - 在StatementHandler.prepare之前进行SQL改写。 - 保持原有分页与排序不受影响,仅在WHERE后追加条件。 - 异常保护:当上下文缺失或表未配置时,回退为最小权限或跳过注入。 ```mermaid flowchart TD Start(["开始"]) --> Parse["解析注解与上下文"] Parse --> MapCheck{"表已配置?"} MapCheck --> |否| Skip["跳过注入"] MapCheck --> |是| Gen["生成条件片段"] Gen --> Inject["注入到SQL"] Inject --> Execute["执行SQL"] Skip --> Execute Execute --> End(["结束"]) ``` **图表来源** - [CrmSqlInjector.java](file://crm-base/src/main/java/com/crm/base/config/CrmSqlInjector.java) - [DataScopeInterceptor.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeInterceptor.java) - [DataScopeTables.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeTables.java) **章节来源** - [CrmSqlInjector.java](file://crm-base/src/main/java/com/crm/base/config/CrmSqlInjector.java) - [DataScopeInterceptor.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeInterceptor.java) - [DataScopeTables.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeTables.java) ## 依赖关系分析 - 组件耦合 - DataScopeInterceptor强依赖DataScopeHelper与DataScopeTables,弱依赖CrmSqlInjector。 - DataScopeHelper依赖DataVisibilityContext与SecurityUtils,间接依赖LoginUser。 - CrmSqlInjector依赖MybatisPlusConfig进行插件注册。 - 外部依赖 - MyBatis拦截器API、MyBatis Plus的SQL重写能力。 - 部门与用户服务用于“本部门及以下”范围的子树查询。 ```mermaid graph LR Interceptor["DataScopeInterceptor"] --> Helper["DataScopeHelper"] Interceptor --> Tables["DataScopeTables"] Interceptor --> Injector["CrmSqlInjector"] Helper --> Context["DataVisibilityContext"] Helper --> Utils["SecurityUtils"] Utils --> User["LoginUser"] Injector --> Config["MybatisPlusConfig"] ``` **图表来源** - [DataScopeInterceptor.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeInterceptor.java) - [DataScopeHelper.java](file://crm-base/src/main/java/com/crm/base/security/DataScopeHelper.java) - [DataScopeTables.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeTables.java) - [CrmSqlInjector.java](file://crm-base/src/main/java/com/crm/base/config/CrmSqlInjector.java) - [MybatisPlusConfig.java](file://crm-base/src/main/java/com/crm/base/config/MybatisPlusConfig.java) - [DataVisibilityContext.java](file://crm-base/src/main/java/com/crm/base/security/DataVisibilityContext.java) - [SecurityUtils.java](file://crm-base/src/main/java/com/crm/base/security/SecurityUtils.java) - [LoginUser.java](file://crm-base/src/main/java/com/crm/base/security/LoginUser.java) **章节来源** - [DataScopeInterceptor.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeInterceptor.java) - [DataScopeHelper.java](file://crm-base/src/main/java/com/crm/base/security/DataScopeHelper.java) - [DataScopeTables.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeTables.java) - [CrmSqlInjector.java](file://crm-base/src/main/java/com/crm/base/config/CrmSqlInjector.java) - [MybatisPlusConfig.java](file://crm-base/src/main/java/com/crm/base/config/MybatisPlusConfig.java) - [DataVisibilityContext.java](file://crm-base/src/main/java/com/crm/base/security/DataVisibilityContext.java) - [SecurityUtils.java](file://crm-base/src/main/java/com/crm/base/security/SecurityUtils.java) - [LoginUser.java](file://crm-base/src/main/java/com/crm/base/security/LoginUser.java) ## 性能考虑 - 上下文缓存 - DataVisibilityContext在同一请求内复用,避免重复解析用户与部门信息。 - 部门树缓存 - “本部门及以下”范围涉及的部门子树查询应加入缓存(如Redis或内存缓存),降低频繁树遍历开销。 - 表级开关 - 通过DataScopeTables的enabled标志,按需启用数据权限,减少不必要的SQL改写。 - SQL片段复用 - 相同级别与字段的条件片段可缓存,避免每次生成字符串拼接。 - 分页与索引 - 确保dept_id、owner_id等字段有合适索引,避免IN子查询导致的全表扫描。 [本节为通用性能建议,不直接分析具体文件] ## 故障排查指南 - 常见问题 - 未配置DataScopeTables导致注入失败:检查表映射是否注册。 - 上下文缺失导致权限降级:确认登录用户与安全上下文是否正确设置。 - 部门树查询缓慢:检查缓存与索引,必要时优化子树查询算法。 - 注解字段名不匹配:核对DataScope注解字段与实体字段一致性。 - 调试手段 - 打印拦截器日志,观察SQL改写前后差异。 - 使用集成测试验证不同级别下的结果集是否符合预期。 **章节来源** - [DataScopeIntegrationTest.java](file://crm-auth/src/test/java/com/crm/auth/security/scope/DataScopeIntegrationTest.java) ## 结论 该数据权限控制方案通过注解驱动的声明式配置、拦截器与SQL注入器的协同工作,实现了灵活且高效的数据范围控制。借助DataScopeTables的表级元数据管理,系统可在不影响业务代码的前提下,精准地为不同级别的数据访问注入过滤条件。结合上下文缓存与部门树缓存,整体性能可控,适用于多租户、多部门协作的CRM场景。 [本节为总结性内容,不直接分析具体文件] ## 附录:配置与使用示例 - 配置示例 - 在DataScopeTables中注册需要数据权限控制的表与字段映射,并启用权限。 - 在MybatisPlusConfig中注册CrmSqlInjector与拦截器。 - 使用示例 - 在Service或Controller方法上添加@DataScope注解,指定级别与字段。 - 对于“本部门及以下”范围,确保部门服务提供子树查询能力。 - 测试示例 - 参考集成测试用例,验证不同级别下的数据过滤效果。 **章节来源** - [DataScopeTables.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeTables.java) - [MybatisPlusConfig.java](file://crm-base/src/main/java/com/crm/base/config/MybatisPlusConfig.java) - [DataScope.java](file://crm-base/src/main/java/com/crm/base/annotation/DataScope.java) - [DataScopeIntegrationTest.java](file://crm-auth/src/test/java/com/crm/auth/security/scope/DataScopeIntegrationTest.java) - [TestOwnedData.java](file://crm-auth/src/test/java/com/crm/auth/security/scope/TestOwnedData.java) - [TestOwnedDataMapper.java](file://crm-auth/src/test/java/com/crm/auth/security/scope/TestOwnedDataMapper.java) - [AuthServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/AuthServiceImpl.java)