# 数据所有权控制 **本文引用的文件** - [DataOwnership.java](file://crm-base/src/main/java/com/crm/base/security/DataOwnership.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) - [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) - [AuthUser.java](file://crm-auth/src/main/java/com/crm/auth/domain/entity/AuthUser.java) - [SysDept.java](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysDept.java) - [SysUserDept.java](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysUserDept.java) - [AuthUserMapper.java](file://crm-auth/src/main/java/com/crm/auth/mapper/AuthUserMapper.java) - [SysDeptMapper.java](file://crm-auth/src/main/java/com/crm/auth/mapper/SysDeptMapper.java) - [SysUserDeptMapper.java](file://crm-auth/src/main/java/com/crm/auth/mapper/SysUserDeptMapper.java) - [BaseServiceImpl.java](file://crm-base/src/main/java/com/crm/base/service/impl/BaseServiceImpl.java) - [CrmSqlInjector.java](file://crm-base/src/main/java/com/crm/base/config/CrmSqlInjector.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. [附录](#附录) ## 简介 本文件面向数据所有权控制能力,系统性说明 DataOwnership 注解的使用方式与配置项、不同数据范围级别 DataScopeLevel 的定义与应用场景,并给出在 Service 层使用数据所有权注解的实践方法。文档还涵盖如何扩展新的数据范围级别、数据权限验证的拦截机制以及性能优化建议,帮助读者快速掌握并安全落地部门级、用户级和全局级的数据访问控制。 ## 项目结构 本项目将数据所有权控制的核心定义放在基础模块 crm-base 中,具体实现与集成位于认证模块 crm-auth 中: - 基础能力(注解、上下文、工具)集中在 crm-base 的安全包下 - 拦截器、表映射、枚举与实体模型集中在 crm-auth 的安全包与领域模型中 - 测试用例覆盖端到端的数据范围校验流程 ```mermaid graph TB subgraph "基础模块 crm-base" A["DataOwnership 注解"] B["DataScopeLevel 枚举"] C["DataScopeHelper 工具"] D["DataVisibilityContext 上下文"] E["LoginUser 登录主体"] F["SecurityUtils 安全工具"] G["BaseServiceImpl 基类服务"] H["CrmSqlInjector SQL注入器"] end subgraph "认证模块 crm-auth" I["DataScopeInterceptor 拦截器"] J["DataScopeTables 表映射"] K["DataScopeEnum 数据范围枚举"] L["AuthUser 用户实体"] M["SysDept 部门实体"] N["SysUserDept 用户-部门关联"] O["AuthUserMapper / SysDeptMapper / SysUserDeptMapper"] end A --> C B --> C C --> D D --> I I --> J I --> O I --> K L --> O M --> O N --> O G --> H ``` 图表来源 - [DataOwnership.java](file://crm-base/src/main/java/com/crm/base/security/DataOwnership.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) - [BaseServiceImpl.java](file://crm-base/src/main/java/com/crm/base/service/impl/BaseServiceImpl.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) - [DataScopeEnum.java](file://crm-auth/src/main/java/com/crm/auth/domain/enums/DataScopeEnum.java) - [AuthUser.java](file://crm-auth/src/main/java/com/crm/auth/domain/entity/AuthUser.java) - [SysDept.java](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysDept.java) - [SysUserDept.java](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysUserDept.java) - [AuthUserMapper.java](file://crm-auth/src/main/java/com/crm/auth/mapper/AuthUserMapper.java) - [SysDeptMapper.java](file://crm-auth/src/main/java/com/crm/auth/mapper/SysDeptMapper.java) - [SysUserDeptMapper.java](file://crm-auth/src/main/java/com/crm/auth/mapper/SysUserDeptMapper.java) 章节来源 - [DataOwnership.java](file://crm-base/src/main/java/com/crm/base/security/DataOwnership.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) - [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) ## 核心组件 - DataOwnership 注解:用于标注 Service 方法或类,声明该方法的数据所有权策略与范围级别 - DataScopeLevel:定义数据范围级别(如部门级、用户级、全局级等),决定查询时自动附加的过滤条件 - DataScopeHelper:提供计算当前可见数据范围的辅助方法,结合上下文与用户信息生成过滤条件 - DataVisibilityContext:线程局部上下文,承载当前请求的数据可见性范围、租户信息等 - LoginUser 与 SecurityUtils:封装当前登录用户信息与获取方式 - DataScopeInterceptor:拦截器,解析注解、读取上下文、组装 SQL 片段并注入到查询语句 - DataScopeTables:维护表名与字段名的映射,确保 SQL 片段正确注入 - BaseServiceImpl 与 CrmSqlInjector:在 MyBatis-Plus 层面统一注入数据范围条件 章节来源 - [DataOwnership.java](file://crm-base/src/main/java/com/crm/base/security/DataOwnership.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) - [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) - [BaseServiceImpl.java](file://crm-base/src/main/java/com/crm/base/service/impl/BaseServiceImpl.java) - [CrmSqlInjector.java](file://crm-base/src/main/java/com/crm/base/config/CrmSqlInjector.java) ## 架构总览 数据所有权控制的执行链路如下: - 调用方进入 Service 方法前,由 DataScopeInterceptor 解析 DataOwnership 注解 - 根据 DataScopeLevel 与当前 LoginUser 的信息,通过 DataScopeHelper 计算可见范围 - 将范围条件注入到 SQL 中(通过 CrmSqlInjector 与 DataScopeTables 映射) - 查询返回结果即已按数据范围过滤 ```mermaid sequenceDiagram participant Client as "客户端" participant Interceptor as "DataScopeInterceptor" participant Context as "DataVisibilityContext" participant Helper as "DataScopeHelper" participant Mapper as "MyBatis Mapper" participant DB as "数据库" Client->>Interceptor : "进入受保护的方法" Interceptor->>Interceptor : "解析 DataOwnership 注解" Interceptor->>Context : "设置/读取可见范围上下文" Interceptor->>Helper : "计算数据范围条件" Helper-->>Interceptor : "返回过滤条件" Interceptor->>Mapper : "注入 SQL 片段" Mapper->>DB : "执行带条件的查询" DB-->>Client : "返回已过滤的结果集" ``` 图表来源 - [DataScopeInterceptor.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeInterceptor.java) - [DataVisibilityContext.java](file://crm-base/src/main/java/com/crm/base/security/DataVisibilityContext.java) - [DataScopeHelper.java](file://crm-base/src/main/java/com/crm/base/security/DataScopeHelper.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) ## 详细组件分析 ### DataOwnership 注解与 DataScopeLevel 级别 - DataOwnership 注解用于声明方法或类的数据所有权策略,包括范围级别、是否强制校验、是否忽略某些表等 - DataScopeLevel 定义不同数据范围级别,常见包括: - 部门级:仅可见本部门及子部门数据 - 用户级:仅可见本人数据 - 全局级:可见全部数据(通常用于管理员) - 注解可配合自定义规则,例如指定特定字段作为归属标识(如 owner_id、dept_id) 章节来源 - [DataOwnership.java](file://crm-base/src/main/java/com/crm/base/security/DataOwnership.java) - [DataScopeLevel.java](file://crm-base/src/main/java/com/crm/base/security/DataScopeLevel.java) #### 类图(注解与级别) ```mermaid classDiagram class DataOwnership { +scopeLevel() +forceCheck() +ignoreTables() +ownerField() } class DataScopeLevel { <> +DEPT +USER +GLOBAL } DataOwnership --> DataScopeLevel : "引用" ``` 图表来源 - [DataOwnership.java](file://crm-base/src/main/java/com/crm/base/security/DataOwnership.java) - [DataScopeLevel.java](file://crm-base/src/main/java/com/crm/base/security/DataScopeLevel.java) ### 上下文与工具:DataVisibilityContext、DataScopeHelper、LoginUser、SecurityUtils - DataVisibilityContext:保存当前请求的数据可见范围、租户 ID、操作人等上下文信息 - DataScopeHelper:根据上下文与用户信息计算数据范围条件(如 dept_id IN (...) 或 owner_id = ?) - LoginUser:封装当前登录用户的基本信息(用户ID、部门ID、角色等) - SecurityUtils:提供从安全上下文中获取 LoginUser 的工具方法 章节来源 - [DataVisibilityContext.java](file://crm-base/src/main/java/com/crm/base/security/DataVisibilityContext.java) - [DataScopeHelper.java](file://crm-base/src/main/java/com/crm/base/security/DataScopeHelper.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) #### 类图(上下文与工具) ```mermaid classDiagram class DataVisibilityContext { +setScope(scope) +getScope() +setTenantId(id) +getTenantId() } class DataScopeHelper { +computeScopeCondition(level, user) +buildDeptFilter(deptIds) +buildOwnerFilter(ownerId) } class LoginUser { +userId +deptId +roles } class SecurityUtils { +getCurrentUser() } DataScopeHelper --> DataVisibilityContext : "读写上下文" DataScopeHelper --> LoginUser : "读取用户信息" SecurityUtils --> LoginUser : "获取当前用户" ``` 图表来源 - [DataVisibilityContext.java](file://crm-base/src/main/java/com/crm/base/security/DataVisibilityContext.java) - [DataScopeHelper.java](file://crm-base/src/main/java/com/crm/base/security/DataScopeHelper.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) ### 拦截器与表映射:DataScopeInterceptor、DataScopeTables - DataScopeInterceptor:在方法执行前解析 DataOwnership 注解,依据 DataScopeLevel 与用户信息计算过滤条件,并将条件注入到 SQL - DataScopeTables:维护表名与字段映射,确保 SQL 片段注入到正确的表与字段上 章节来源 - [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) #### 序列图(拦截流程) ```mermaid sequenceDiagram participant Svc as "Service方法" participant Int as "DataScopeInterceptor" participant Tbl as "DataScopeTables" participant Sql as "SQL注入器" Svc->>Int : "进入受保护方法" Int->>Int : "解析 DataOwnership" Int->>Tbl : "查找表字段映射" Int->>Sql : "注入 WHERE 条件" Sql-->>Svc : "返回带条件的查询" ``` 图表来源 - [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、AuthUser、SysDept、SysUserDept - DataScopeEnum:定义系统内数据范围枚举值,与 DataScopeLevel 协同使用 - AuthUser:用户实体,包含用户基本信息与所属部门 - SysDept:部门实体,支持层级结构 - SysUserDept:用户与部门的关联表,用于多部门归属 章节来源 - [DataScopeEnum.java](file://crm-auth/src/main/java/com/crm/auth/domain/enums/DataScopeEnum.java) - [AuthUser.java](file://crm-auth/src/main/java/com/crm/auth/domain/entity/AuthUser.java) - [SysDept.java](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysDept.java) - [SysUserDept.java](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysUserDept.java) #### 类图(实体与枚举) ```mermaid classDiagram class DataScopeEnum { <> +DEPT +USER +GLOBAL } class AuthUser { +id +name +deptId } class SysDept { +id +parentId +name } class SysUserDept { +userId +deptId } AuthUser --> SysDept : "属于" AuthUser --> SysUserDept : "关联" SysDept --> SysUserDept : "被关联" ``` 图表来源 - [DataScopeEnum.java](file://crm-auth/src/main/java/com/crm/auth/domain/enums/DataScopeEnum.java) - [AuthUser.java](file://crm-auth/src/main/java/com/crm/auth/domain/entity/AuthUser.java) - [SysDept.java](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysDept.java) - [SysUserDept.java](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysUserDept.java) ### Service 层使用示例与扩展新级别 - 在 Service 方法上使用 DataOwnership 注解,指定 DataScopeLevel 与必要参数(如 ownerField) - 若需新增数据范围级别,可在 DataScopeLevel 中添加枚举值,并在 DataScopeHelper 中补充对应计算逻辑 - 建议在 BaseServiceImpl 中统一处理通用数据范围注入,减少重复代码 章节来源 - [BaseServiceImpl.java](file://crm-base/src/main/java/com/crm/base/service/impl/BaseServiceImpl.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) #### 流程图(扩展新级别) ```mermaid flowchart TD Start(["开始"]) --> AddEnum["在 DataScopeLevel 添加新级别"] AddEnum --> UpdateHelper["在 DataScopeHelper 实现新级别的计算逻辑"] UpdateHelper --> UpdateTables["在 DataScopeTables 配置新级别对应的表字段映射"] UpdateTables --> Test["编写单元测试验证"] Test --> End(["完成"]) ``` 图表来源 - [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) - [DataScopeTables.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeTables.java) ### 数据权限验证的拦截机制 - DataScopeInterceptor 负责解析注解、读取上下文、计算范围条件并注入 SQL - 若未检测到有效登录用户或范围级别不合法,应抛出权限异常 - 可通过 CrmSqlInjector 统一注入 WHERE 条件,保证所有查询均受控 章节来源 - [DataScopeInterceptor.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeInterceptor.java) - [CrmSqlInjector.java](file://crm-base/src/main/java/com/crm/base/config/CrmSqlInjector.java) #### 序列图(权限验证) ```mermaid sequenceDiagram participant Req as "请求" participant Int as "DataScopeInterceptor" participant Sec as "SecurityUtils" participant Hlp as "DataScopeHelper" participant Inj as "CrmSqlInjector" Req->>Int : "进入方法" Int->>Sec : "获取当前用户" Sec-->>Int : "返回 LoginUser" Int->>Hlp : "计算数据范围" Hlp-->>Int : "返回过滤条件" Int->>Inj : "注入 SQL 条件" Inj-->>Req : "执行受控查询" ``` 图表来源 - [DataScopeInterceptor.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeInterceptor.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) - [CrmSqlInjector.java](file://crm-base/src/main/java/com/crm/base/config/CrmSqlInjector.java) ## 依赖关系分析 - DataOwnership 注解依赖 DataScopeLevel 枚举 - DataScopeHelper 依赖 DataVisibilityContext、LoginUser 与安全工具 - DataScopeInterceptor 依赖 DataScopeTables、DataScopeHelper 与 SQL 注入器 - BaseServiceImpl 与 CrmSqlInjector 共同完成 MyBatis-Plus 层面的条件注入 ```mermaid graph LR A["DataOwnership"] --> B["DataScopeLevel"] C["DataScopeHelper"] --> D["DataVisibilityContext"] C --> E["LoginUser"] F["DataScopeInterceptor"] --> G["DataScopeTables"] F --> C F --> H["CrmSqlInjector"] I["BaseServiceImpl"] --> H ``` 图表来源 - [DataOwnership.java](file://crm-base/src/main/java/com/crm/base/security/DataOwnership.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) - [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) - [BaseServiceImpl.java](file://crm-base/src/main/java/com/crm/base/service/impl/BaseServiceImpl.java) - [CrmSqlInjector.java](file://crm-base/src/main/java/com/crm/base/config/CrmSqlInjector.java) 章节来源 - [DataOwnership.java](file://crm-base/src/main/java/com/crm/base/security/DataOwnership.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) - [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) - [BaseServiceImpl.java](file://crm-base/src/main/java/com/crm/base/service/impl/BaseServiceImpl.java) - [CrmSqlInjector.java](file://crm-base/src/main/java/com/crm/base/config/CrmSqlInjector.java) ## 性能考虑 - 避免在每次请求中重复计算用户部门树:对部门层级进行缓存,减少递归查询 - 合理设计 DataScopeTables 映射,避免不必要的表扫描;为常用过滤字段建立索引 - 在 DataScopeHelper 中尽量使用集合批量查询,减少多次 IO - 对于大数据量查询,优先在数据库侧进行过滤,避免将大量数据拉取到内存再过滤 - 使用分页查询并结合数据范围条件,降低单次查询压力 [本节为通用指导,无需具体文件来源] ## 故障排查指南 - 常见问题: - 未正确配置 DataScopeTables 导致 SQL 注入失败 - 当前用户为空或权限不足导致范围计算异常 - 数据范围级别与业务字段不匹配导致查询结果为空 - 排查步骤: - 检查 DataOwnership 注解的参数是否正确 - 确认 DataScopeLevel 与业务字段一致 - 查看 DataScopeHelper 计算的过滤条件是否符合预期 - 检查数据库索引与 SQL 执行计划 章节来源 - [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) - [DataScopeHelper.java](file://crm-base/src/main/java/com/crm/base/security/DataScopeHelper.java) ## 结论 数据所有权控制通过注解驱动与拦截器机制,实现了灵活且可扩展的数据范围管理。借助 DataOwnership 与 DataScopeLevel,开发者可以便捷地在 Service 层声明数据访问策略,并通过统一的拦截与注入机制保障数据安全。建议在生产环境中结合缓存、索引与分页等手段优化性能,同时完善测试覆盖以确保行为稳定。 [本节为总结性内容,无需具体文件来源] ## 附录 - 端到端测试参考: - 数据范围集成测试:[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) 章节来源 - [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)