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.
18 KiB
18 KiB
数据范围助手
**本文引用的文件** - [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) - [DataScopeLevel.java](file://crm-base/src/main/java/com/crm/base/security/DataScopeLevel.java) - [DataOwnership.java](file://crm-base/src/main/java/com/crm/base/security/DataOwnership.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) - [DataScope.java](file://crm-base/src/main/java/com/crm/base/annotation/DataScope.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) - [DataScopeIntegrationTest.java](file://crm-auth/src/test/java/com/crm/auth/security/scope/DataScopeIntegrationTest.java) - [DataVisibilityTest.java](file://crm-base/src/test/java/com/crm/base/security/DataVisibilityTest.java)目录
简介
本文件为“数据范围助手”提供全面文档,聚焦于 DataScopeHelper 工具类与 DataVisibilityContext 上下文管理机制。内容涵盖:
- 数据范围的设置、获取与清理操作
- 线程安全的数据可见性控制与跨方法调用时的数据范围传递
- 在业务逻辑中动态调整数据访问范围的实际使用模式
- 常见用法、最佳实践、异常处理与数据一致性保证
项目结构
围绕数据范围能力的相关代码主要分布在基础模块与安全模块中:
- 基础模块(crm-base)提供数据范围的核心工具与上下文管理
- 认证模块(crm-auth)提供拦截器与表级配置,将数据范围注入到查询条件中
- 测试用例覆盖集成与上下文行为验证
graph TB
subgraph "基础模块 crm-base"
A["DataScopeHelper<br/>数据范围工具"]
B["DataVisibilityContext<br/>可见性上下文"]
C["DataScopeLevel<br/>数据范围级别"]
D["DataOwnership<br/>数据所有权注解"]
E["LoginUser<br/>登录用户信息"]
F["SecurityUtils<br/>安全工具"]
G["DataScope 注解<br/>声明式数据范围"]
end
subgraph "认证模块 crm-auth"
H["DataScopeInterceptor<br/>数据范围拦截器"]
I["DataScopeTables<br/>数据范围表配置"]
end
A --> B
A --> C
A --> E
A --> F
H --> I
H --> A
G --> H
图表来源
- DataScopeHelper.java
- DataVisibilityContext.java
- DataScopeLevel.java
- DataOwnership.java
- LoginUser.java
- SecurityUtils.java
- DataScope.java
- DataScopeInterceptor.java
- DataScopeTables.java
章节来源
- DataScopeHelper.java
- DataVisibilityContext.java
- DataScopeInterceptor.java
- DataScopeTables.java
核心组件
- DataScopeHelper:提供数据范围的设置、获取、合并与清理等工具方法,支持按级别与表维度进行控制。
- DataVisibilityContext:基于线程局部变量的上下文容器,确保同一线程内数据范围的一致性与隔离性。
- DataScopeLevel:定义数据范围级别(如全部、本部门、本人等),用于限定可访问数据的边界。
- DataOwnership:注解,用于声明某实体或方法对特定数据的所有权,辅助范围推导。
- LoginUser:封装当前登录用户信息,作为数据范围计算的基础。
- SecurityUtils:安全相关工具,常用于从上下文中提取当前用户或权限信息。
- DataScope 注解:声明式标注接口或方法,配合拦截器自动注入数据范围过滤条件。
- DataScopeInterceptor:拦截请求,解析注解与表配置,将数据范围条件注入到 SQL 查询中。
- DataScopeTables:维护需要应用数据范围的表清单及映射规则。
章节来源
- DataScopeHelper.java
- DataVisibilityContext.java
- DataScopeLevel.java
- DataOwnership.java
- LoginUser.java
- SecurityUtils.java
- DataScope.java
- DataScopeInterceptor.java
- DataScopeTables.java
架构总览
数据范围的整体流程如下:
- 请求进入时,拦截器根据注解与表配置确定目标表与范围级别
- 通过工具类从当前用户与上下文推导出最终的数据范围集合
- 将范围条件注入到查询语句中,实现行级数据隔离
- 上下文在同一线程内保持可见性,跨方法调用无需显式传递
sequenceDiagram
participant Client as "客户端"
participant Interceptor as "数据范围拦截器"
participant Helper as "数据范围助手"
participant Context as "可见性上下文"
participant DB as "数据库"
Client->>Interceptor : "HTTP 请求"
Interceptor->>Interceptor : "解析 @DataScope 与表配置"
Interceptor->>Helper : "计算数据范围(用户+级别)"
Helper->>Context : "读取/设置当前范围"
Context-->>Helper : "返回范围集合"
Helper-->>Interceptor : "返回范围条件"
Interceptor->>DB : "执行带范围条件的查询"
DB-->>Client : "返回受限结果集"
图表来源
- DataScopeInterceptor.java
- DataScopeHelper.java
- DataVisibilityContext.java
- DataScopeTables.java
详细组件分析
DataScopeHelper:数据范围工具
职责与方法概览:
- 设置数据范围:为当前线程设置指定级别与表维度的范围集合
- 获取数据范围:从上下文中读取当前有效的范围集合
- 合并数据范围:将多个范围集合合并去重,形成最终范围
- 清理数据范围:在方法结束后恢复或清空上下文中的范围,避免泄漏
- 范围推导:结合当前用户信息与级别枚举,生成初始范围
典型使用场景:
- 在业务方法中临时扩大或缩小数据访问范围
- 在异步任务或子线程中继承父线程的范围上下文
- 在批量操作中统一设置范围,减少重复计算
flowchart TD
Start(["进入方法"]) --> CheckCtx["检查上下文是否已有范围"]
CheckCtx --> HasRange{"存在范围?"}
HasRange --> |是| UseExisting["沿用现有范围"]
HasRange --> |否| Compute["根据用户与级别计算范围"]
Compute --> SetCtx["写入上下文"]
UseExisting --> Execute["执行业务逻辑"]
SetCtx --> Execute
Execute --> Cleanup["清理/恢复上下文"]
Cleanup --> End(["退出方法"])
图表来源
- DataScopeHelper.java
- DataVisibilityContext.java
- DataScopeLevel.java
章节来源
- DataScopeHelper.java
- DataVisibilityContext.java
- DataScopeLevel.java
DataVisibilityContext:可见性上下文
设计要点:
- 线程安全:基于 ThreadLocal 存储当前线程的数据范围集合,确保并发隔离
- 作用域管理:在进入方法前设置范围,退出时清理,防止上下文污染
- 继承与传播:支持在子线程创建时复制父线程范围,便于异步任务继承上下文
关键操作:
- 设置范围:setScope(level, table, scopeSet)
- 获取范围:getScope(level, table)
- 清理范围:clearScope(level, table) 或 clearAll()
classDiagram
class DataVisibilityContext {
+setScope(level, table, scopeSet) void
+getScope(level, table) Set~String~
+clearScope(level, table) void
+clearAll() void
-threadLocalScope Map~String, Set~String~~
}
图表来源
- DataVisibilityContext.java
章节来源
- DataVisibilityContext.java
DataScopeLevel:数据范围级别
说明:
- 定义不同粒度的数据访问级别,例如全部、本部门、本人等
- 与用户信息结合,生成具体的数据范围集合(如部门ID列表、用户ID列表)
章节来源
- DataScopeLevel.java
DataOwnership:数据所有权注解
说明:
- 标注实体或方法,表示其对某些数据的所有权关系
- 辅助范围推导,例如默认将所有者ID加入范围集合
章节来源
- DataOwnership.java
LoginUser 与 SecurityUtils:用户与安全工具
说明:
- LoginUser 封装当前登录用户的关键属性(如用户ID、部门ID、角色等)
- SecurityUtils 提供便捷方法从安全上下文获取当前用户或权限信息
章节来源
- LoginUser.java
- SecurityUtils.java
DataScope 注解与 DataScopeInterceptor:声明式范围注入
说明:
- DataScope 注解用于在接口或方法上声明数据范围级别与目标表
- DataScopeInterceptor 拦截请求,解析注解与表配置,将范围条件注入到查询中
sequenceDiagram
participant Controller as "控制器"
participant Interceptor as "数据范围拦截器"
participant Tables as "表配置"
participant Helper as "数据范围助手"
participant Mapper as "数据访问层"
Controller->>Interceptor : "调用被 @DataScope 标注的方法"
Interceptor->>Tables : "读取目标表与级别映射"
Interceptor->>Helper : "计算并获取范围集合"
Helper-->>Interceptor : "返回范围条件"
Interceptor->>Mapper : "执行带范围条件的查询"
Mapper-->>Controller : "返回受限结果"
图表来源
- DataScope.java
- DataScopeInterceptor.java
- DataScopeTables.java
- DataScopeHelper.java
章节来源
- DataScope.java
- DataScopeInterceptor.java
- DataScopeTables.java
依赖关系分析
- DataScopeHelper 依赖 DataVisibilityContext 进行范围存取,依赖 DataScopeLevel 与 LoginUser 进行范围推导
- DataScopeInterceptor 依赖 DataScopeTables 与 DataScopeHelper,负责将范围注入到查询
- 测试用例验证上下文行为与拦截器集成效果
graph LR
Helper["DataScopeHelper"] --> Ctx["DataVisibilityContext"]
Helper --> Level["DataScopeLevel"]
Helper --> User["LoginUser"]
Interceptor["DataScopeInterceptor"] --> Helper
Interceptor --> Tables["DataScopeTables"]
Test1["DataScopeIntegrationTest"] --> Interceptor
Test2["DataVisibilityTest"] --> Ctx
图表来源
- DataScopeHelper.java
- DataVisibilityContext.java
- DataScopeLevel.java
- LoginUser.java
- DataScopeInterceptor.java
- DataScopeTables.java
- DataScopeIntegrationTest.java
- DataVisibilityTest.java
章节来源
- DataScopeHelper.java
- DataVisibilityContext.java
- DataScopeInterceptor.java
- DataScopeTables.java
- DataScopeIntegrationTest.java
- DataVisibilityTest.java
性能考量
- 上下文存取开销低:ThreadLocal 的 get/set 操作为 O(1),适合高频调用
- 范围集合大小影响查询性能:范围过大可能导致 SQL IN 条件过长,建议分页或分批处理
- 缓存策略:对于稳定的范围集合(如部门成员列表)可考虑缓存,减少重复计算
- 清理时机:务必在方法结束或异常分支中清理上下文,避免内存泄漏与上下文污染
[本节为通用指导,不直接分析具体文件]
故障排查指南
常见问题与定位思路:
- 数据范围未生效
- 检查是否在请求入口正确设置范围
- 确认 @DataScope 注解与表配置是否正确
- 查看拦截器是否被启用且顺序正确
- 上下文泄漏导致范围污染
- 确保每个方法在 finally 块中清理范围
- 检查异步任务是否正确复制与清理上下文
- 范围过大导致查询缓慢
- 优化范围集合,增加过滤条件
- 使用分页或分批次查询
章节来源
- DataScopeIntegrationTest.java
- DataVisibilityTest.java
结论
DataScopeHelper 与 DataVisibilityContext 共同构成了灵活、线程安全的数据范围控制体系。通过注解与拦截器的声明式注入,开发者可以在不侵入业务逻辑的前提下实现细粒度的数据隔离。遵循最佳实践与清理规范,可有效避免上下文污染与性能问题,保障数据一致性与系统稳定性。
[本节为总结,不直接分析具体文件]
附录
- 使用示例路径参考:
- 集成测试:DataScopeIntegrationTest.java
- 上下文行为测试:DataVisibilityTest.java
- 关键类路径参考:
- 数据范围工具:DataScopeHelper.java
- 可见性上下文:DataVisibilityContext.java
- 范围级别:DataScopeLevel.java
- 数据所有权注解:DataOwnership.java
- 登录用户信息:LoginUser.java
- 安全工具:SecurityUtils.java
- 声明式注解:DataScope.java
- 拦截器:DataScopeInterceptor.java
- 表配置:DataScopeTables.java