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.
475 lines
26 KiB
475 lines
26 KiB
|
1 month ago
|
# 数据权限控制
|
||
|
|
|
||
|
|
<cite>
|
||
|
|
**本文引用的文件**
|
||
|
|
- [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)
|
||
|
|
</cite>
|
||
|
|
|
||
|
|
## 目录
|
||
|
|
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)
|