# 权限管理系统 **本文引用的文件** - [PermissionResolver.java](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolver.java) - [PermissionGrant.java](file://crm-auth/src/main/java/com/crm/auth/security/PermissionGrant.java) - [PermissionResolverImpl.java](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolverImpl.java) - [SysRoleServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysRoleServiceImpl.java) - [ISysRoleService.java](file://crm-auth/src/main/java/com/crm/auth/service/ISysRoleService.java) - [SysMenuServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysMenuServiceImpl.java) - [AuthConstants.java](file://crm-auth/src/main/java/com/crm/auth/constant/AuthConstants.java) - [SystemController.java](file://crm-auth/src/main/java/com/crm/auth/controller/SystemController.java) - [RoleController.java](file://crm-auth/src/main/java/com/crm/auth/controller/RoleController.java) - [ResourceController.java](file://crm-auth/src/main/java/com/crm/auth/controller/ResourceController.java) - [AuthUserServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/AuthUserServiceImpl.java) - [SysRole.java](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysRole.java) - [SysMenu.java](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysMenu.java) - [RoleDetailVO.java](file://crm-auth/src/main/java/com/crm/auth/domain/dto/RoleDetailVO.java) - [ResourceNode.java](file://crm-auth/src/main/java/com/crm/auth/domain/dto/ResourceNode.java) - [MenuType.java](file://crm-auth/src/main/java/com/crm/auth/domain/enums/MenuType.java) - [DataScopeEnum.java](file://crm-auth/src/main/java/com/crm/auth/domain/enums/DataScopeEnum.java) - [TreeUtils.java](file://crm-base/src/main/java/com/crm/base/utils/TreeUtils.java) - [DataInitializer.java](file://crm-auth/src/main/java/com/crm/auth/config/DataInitializer.java) ## 更新摘要 **所做更改** - **增强的角色管理系统**:实现了完整的角色验证逻辑,包括数据范围限制、内置角色保护和编码唯一性校验 - **祖先补全机制优化**:在资源分配时自动计算并补全菜单ID的祖先节点,确保层级权限的正确性 - **事务安全全面增强**:所有角色相关操作都使用@Transactional注解确保数据一致性和原子性 - **OpenAPI文档完善**:RoleController中添加了全面的@Operation注解,提供完整的API文档支持 - **细粒度权限控制强化**:每个接口都使用@PreAuthorize注解进行精确到按钮级别的权限控制 - **错误处理机制改进**:新增专门的错误码和处理逻辑,提升系统健壮性 ## 目录 1. [简介](#简介) 2. [项目结构](#项目结构) 3. [核心组件](#核心组件) 4. [架构总览](#架构总览) 5. [详细组件分析](#详细组件分析) 6. [依赖关系分析](#依赖关系分析) 7. [性能考虑](#性能考虑) 8. [故障排查指南](#故障排查指南) 9. [结论](#结论) 10. [附录](#附录) ## 简介 本文件为基于RBAC(角色-资源)的权限管理系统文档,覆盖角色管理、菜单权限控制与数据权限范围控制。重点说明实体设计(如 SysRole、SysMenu)、权限校验逻辑(PermissionResolver接口与PermissionGrant值对象)、数据权限类型(DataScopeEnum),以及权限注解使用、动态权限加载与权限缓存机制的实现细节和配置方法。读者可据此快速理解系统权限模型并正确扩展与使用。 **更新** 本次更新重点关注增强的角色管理系统实现,包括复杂的角色验证逻辑、祖先补全机制、事务安全保障和完善的OpenAPI文档支持。系统现已具备企业级的角色管理能力,支持内置角色保护、数据范围限制和精细化的权限控制。 ## 项目结构 本项目采用多模块组织: - crm-app:应用启动入口与全局配置 - crm-auth:认证与权限核心模块,包含RBAC实体、服务、安全拦截、第三方登录等 - crm-base:公共基础能力(异常、工具、通用配置、数据可见性上下文等) - crm-file:文件服务(与本权限文档无直接关联) ```mermaid graph TB subgraph "应用层" APP["crm-app
启动与应用配置"] end subgraph "认证与权限" AUTH["crm-auth
RBAC实体/服务/安全/客户端"] end subgraph "基础能力" BASE["crm-base
异常/工具/通用配置/数据可见性"] end APP --> AUTH AUTH --> BASE ``` 章节来源 - [CrmAppApplication.java:1-200](file://crm-app/src/main/java/com/crm/app/CrmAppApplication.java#L1-L200) - [AuthApplication.java:1-200](file://crm-auth/src/main/java/com/crm/auth/AuthApplication.java#L1-L200) ## 核心组件 - RBAC 实体 - SysRole:增强的角色定义,支持内置角色保护、数据范围限制和状态管理 - SysMenu:增强的菜单与按钮资源定义,支持三层层级结构(目录-菜单-按钮)和细粒度权限控制 - SysUserRole、SysRoleMenu:用户-角色、角色-菜单的多对多关系表,支持祖先补全机制 - SysDept、SysUserDept:部门与用户部门关系,用于数据权限范围 - 数据传输对象 - ResourceNode:支持SysMenu与ResourceNode之间的双向转换,包含children字段支持层次结构 - RoleDetailVO:角色详情视图对象,包含完整的授权资源集合信息 - **新增** 权限解析引擎 - PermissionResolver:权限解析接口,定义resolve()和visibleMenuTree()两个核心方法 - PermissionGrant:权限解析结果值对象,包含数据可见性、权限码集合、角色编码集合 - PermissionResolverImpl:权限解析引擎实现,实现fail-closed安全原则和统一的查询链 - 控制器层 - ResourceController:统一权限资源树管理端接口,提供标准化的RESTful API,支持@PreAuthorize注解 - RoleController:增强的角色管理接口,全面使用@PreAuthorize进行细粒度权限控制,集成OpenAPI文档注解 - SystemController:系统管理相关接口,现在完全通过Service层进行业务处理 - 安全与拦截 - SecurityConfig、JwtAuthenticationFilter:认证流程与JWT过滤 - DataScopeInterceptor、DataScopeTables:数据权限拦截与SQL改写 - AuthLoginUser、TokenService:当前登录用户上下文与令牌操作 - 数据权限 - DataScopeEnum:数据权限范围枚举(如全部、本部门、本部门及子部门、仅本人等) - DataScope(注解)、DataScopeHelper、DataVisibilityContext:注解驱动的数据可见性控制 **更新** 角色管理服务现在具有完整的事务保护机制,所有涉及角色分配的操作都通过@Transactional注解确保数据一致性。Service层整合消除了控制器中的直接Mapper访问,提升了代码的可维护性。新增的@PreAuthorize注解使用实现了细粒度的权限控制,同时集成了全面的OpenAPI文档注解。 章节来源 - [SysRoleServiceImpl.java:30-42](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysRoleServiceImpl.java#L30-L42) - [ISysRoleService.java:9-42](file://crm-auth/src/main/java/com/crm/auth/service/ISysRoleService.java#L9-L42) - [RoleController.java:25-30](file://crm-auth/src/main/java/com/crm/auth/controller/RoleController.java#L25-L30) - [ResourceController.java:22](file://crm-auth/src/main/java/com/crm/auth/controller/ResourceController.java#L22) - [PermissionResolver.java:1-36](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolver.java#L1-36) - [PermissionGrant.java:1-68](file://crm-auth/src/main/java/com/crm/auth/security/PermissionGrant.java#L1-68) - [PermissionResolverImpl.java:1-140](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolverImpl.java#L1-140) ## 架构总览 下图展示重构后的权限系统在请求链路中的关键交互:从JWT鉴权到权限解析,再到数据可见性注入与SQL改写。 ```mermaid sequenceDiagram participant Client as "客户端" participant Filter as "JwtAuthenticationFilter" participant Resolver as "PermissionResolver" participant Grant as "PermissionGrant" participant Service as "业务服务" participant DB as "数据库" Client->>Filter : "HTTP 请求" Filter->>Resolver : "调用权限解析引擎" Resolver->>DB : "执行统一查询链" DB-->>Resolver : "返回用户角色与授权" Resolver-->>Grant : "构建权限授予对象" Grant-->>Filter : "返回权限授予结果" Filter->>Service : "执行业务逻辑" Service-->>Client : "响应请求" ``` **更新** 新的架构通过PermissionResolver接口抽象了权限解析逻辑,PermissionGrant作为不可变的值对象传递权限信息,实现了更好的职责分离和线程安全性。同时,Service层的事务保护确保了数据操作的原子性。@PreAuthorize注解提供了细粒度的权限控制能力,RoleController集成了全面的OpenAPI文档注解。 图表来源 - [SecurityConfig.java:1-200](file://crm-auth/src/main/java/com/crm/auth/config/SecurityConfig.java#L1-L200) - [JwtAuthenticationFilter.java:1-200](file://crm-auth/src/main/java/com/crm/auth/security/JwtAuthenticationFilter.java#L1-L200) - [PermissionResolver.java:1-36](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolver.java#L1-36) - [PermissionGrant.java:1-68](file://crm-auth/src/main/java/com/crm/auth/security/PermissionGrant.java#L1-68) - [PermissionResolverImpl.java:1-140](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolverImpl.java#L1-140) ## 详细组件分析 ### 增强的角色管理系统与验证逻辑 **新增** SysRoleServiceImpl实现了完整的角色验证逻辑,包含多层次的安全检查和业务规则: - **基础非空校验**:角色名称和编码必填验证 - **数据范围限制**:禁止使用CUSTOM自定义数据范围,只允许预定义的范围类型 - **内置角色保护**: - 创建保护:不允许通过接口创建builtin=true的角色 - 修改保护:内置角色的roleCode不可修改 - 删除保护:内置角色不允许删除 - **编码唯一性校验**:确保角色编码的全局唯一性 ```mermaid flowchart TD Start(["角色保存开始"]) --> CheckEmpty{"检查必填字段"} CheckEmpty --> |通过| CheckDataScope{"检查数据范围合法性"} CheckEmpty --> |失败| Error1["抛出参数非法异常"] CheckDataScope --> |合法| CheckBuiltin{"检查内置角色保护"} CheckDataScope --> |非法| Error2["抛出不合法数据范围异常"] CheckBuiltin --> |新建且为内置| Error3["抛出内置角色保护异常"] CheckBuiltin --> |编辑且改编码| Error4["抛出内置角色保护异常"] CheckBuiltin --> |正常| CheckDuplicate{"检查编码唯一性"} CheckDuplicate --> |重复| Error5["抛出编码重复异常"] CheckDuplicate --> |唯一| SaveSuccess["保存成功"] Error1 --> End(["结束"]) Error2 --> End Error3 --> End Error4 --> End Error5 --> End SaveSuccess --> End ``` **更新** 新的验证逻辑确保了角色数据的完整性和安全性,防止非法操作和数据不一致问题。 章节来源 - [SysRoleServiceImpl.java:44-86](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysRoleServiceImpl.java#L44-L86) ### 祖先补全机制优化 **新增** 系统实现了高效的祖先补全机制,确保层级权限的正确继承: - **批量查询优化**:一次性获取所有菜单数据,构建ID→parentId映射 - **内存遍历算法**:在内存中向上遍历父节点,避免多次数据库查询 - **去重处理**:使用LinkedHashSet确保结果集的唯一性和插入顺序 - **循环检测**:防止因数据异常导致的无限循环 ```mermaid flowchart TD Start(["祖先补全开始"]) --> CheckInput{"检查输入是否为空"} CheckInput --> |为空| ReturnEmpty["返回空集合"] CheckInput --> |非空| LoadAllMenus["加载所有菜单数据"] LoadAllMenus --> BuildMap["构建ID→parentId映射"] BuildMap --> ProcessEach["处理每个输入节点"] ProcessEach --> TraverseUp["沿parentId向上遍历"] TraverseUp --> AddAncestor["添加祖先节点到结果集"] AddAncestor --> Continue{"是否还有父节点?"} Continue --> |是| TraverseUp Continue --> |否| NextNode["处理下一个节点"] NextNode --> ProcessEach ReturnEmpty --> End(["结束"]) End ``` **更新** 祖先补全机制显著提升了性能,避免了N+1查询问题,同时保证了层级权限的完整性。 章节来源 - [SysMenuServiceImpl.java:17-41](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysMenuServiceImpl.java#L17-L41) ### 事务安全全面增强 **新增** 所有角色相关操作都配备了完整的事务保护机制: - **assignResources方法**:使用@Transactional注解确保角色-菜单关联操作的事务完整性 - **deleteRoleCascade方法**:级联删除操作在事务中执行,保证数据一致性 - **异常回滚**:任何异常都会触发事务回滚,确保数据的一致性 ```mermaid sequenceDiagram participant Client as "客户端" participant Controller as "RoleController" participant Service as "SysRoleServiceImpl" participant Mapper as "SysRoleMenuMapper" participant DB as "数据库" Client->>Controller : "分配角色资源请求" Controller->>Service : "调用assignResources方法" Service->>Service : "@Transactional开始" Service->>Mapper : "删除现有角色-菜单关联" Mapper->>DB : "执行DELETE操作" DB-->>Mapper : "返回删除结果" Service->>Mapper : "批量插入新的角色-菜单关联" Mapper->>DB : "执行INSERT操作" DB-->>Mapper : "返回插入结果" Service->>Service : "事务提交" Service-->>Controller : "返回成功响应" Controller-->>Client : "JSON响应" ``` **更新** 事务保护机制确保了复杂业务操作的原子性,防止部分更新导致的数据不一致问题。 章节来源 - [SysRoleServiceImpl.java:105-122](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysRoleServiceImpl.java#L105-L122) - [SysRoleServiceImpl.java:124-142](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysRoleServiceImpl.java#L124-L142) ### OpenAPI文档注解完善 **新增** RoleController集成了全面的OpenAPI注解,提供完整的API文档支持: - **@Operation注解**:每个接口都有详细的描述和标签分类 - **参数说明**:所有请求参数都有清晰的说明文档 - **响应类型**:明确的返回值类型定义 - **标签分组**:按功能模块对API进行分类管理 ```mermaid classDiagram class RoleController { +page() Result~PageResult~SysRole~~ +saveOrUpdate() Result~Void~ +detail() Result~RoleDetailVO~ +assignResources() Result~Void~ +delete() Result~Void~ } class Operation { +summary : String +tags : String[] } class Schema { +description : String } RoleController --> Operation : "API文档注解" Operation --> Schema : "参数描述" ``` **更新** OpenAPI注解的使用使得API文档自动生成成为可能,大大提升了开发效率和文档维护性。 章节来源 - [RoleController.java:32-96](file://crm-auth/src/main/java/com/crm/auth/controller/RoleController.java#L32-L96) ### 细粒度权限控制与@PreAuthorize注解使用 **新增** 系统现已全面支持基于@PreAuthorize注解的细粒度权限控制,从粗粒度的角色检查演进为精确到按钮级别的权限管理: - **RoleController权限控制**:每个接口都使用@PreAuthorize注解指定具体的权限码 - `hasAuthority('crm:role:list')`:角色列表查询权限 - `hasAuthority('crm:role:save')`:角色保存权限 - `hasAuthority('crm:role:detail')`:角色详情查看权限 - `hasAuthority('crm:role:assign')`:角色权限分配权限 - `hasAuthority('crm:role:delete')`:角色删除权限 - **权限码标准化**:采用`模块:功能:操作`的命名规范,确保权限码的一致性和可读性 ```mermaid flowchart TD Start(["权限验证开始"]) --> CheckAnnotation{"检查@PreAuthorize注解"} CheckAnnotation --> |存在| ExtractAuthority["提取权限码"] ExtractAuthority --> ValidateAuthority["验证用户是否拥有权限"] ValidateAuthority --> |是| AllowAccess["允许访问"] ValidateAuthority --> |否| DenyAccess["拒绝访问"] CheckAnnotation --> |不存在| SkipCheck["跳过权限检查"] SkipCheck --> AllowAccess AllowAccess --> End(["结束"]) DenyAccess --> End ``` **更新** 新的权限控制机制提供了更细粒度的访问控制,每个接口都可以独立配置权限要求,大大提升了系统的安全性。 章节来源 - [RoleController.java:32-96](file://crm-auth/src/main/java/com/crm/auth/controller/RoleController.java#L32-L96) ### 三层资源层级结构设计 系统现在支持完整的三层资源层级结构,通过MenuType枚举定义了目录、菜单、按钮三种资源类型: - **目录(CATALOG)**:作为收纳容器,不承载页面,只能挂menu子节点 - **菜单(MENU)**:可导航的页面,只能挂button子节点 - **按钮(BUTTON)**:叶子节点,不可再挂子节点,承载权限码和接口映射 ```mermaid classDiagram class MenuType { +CATALOG : MenuType +MENU : MenuType +BUTTON : MenuType +fromCode(code) : MenuType +isLegalChild(parent, child) : boolean } class SysMenu { +Long parentId +String menuName +Integer menuType +String path +String component +String icon +Integer sort +Boolean visible +String description +String perms +String denyBehavior +String status +String apiUrl +SysMenu[] children } class ResourceNode { +Long id +Long parentId +String name +MenuType type +Integer sort +String description +String route +String perms +String denyBehavior +String apiUrl +String status +String icon +ResourceNode[] children +fromEntity(entity) : ResourceNode +toEntity() : SysMenu } MenuType <|-- SysMenu SysMenu <..> ResourceNode : 双向转换 ``` 章节来源 - [MenuType.java:12-52](file://crm-auth/src/main/java/com/crm/auth/domain/enums/MenuType.java#L12-52) - [SysMenu.java:12-76](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysMenu.java#L12-76) - [ResourceNode.java:16-84](file://crm-auth/src/main/java/com/crm/auth/domain/dto/ResourceNode.java#L16-84) ### 统一资源树管理系统 完整的资源树管理系统,包含控制器、服务和接口,遵循全局接口契约: #### ResourceController 提供标准化的RESTful API接口,采用显式动作后缀设计: - `GET /api/resources/list`:**获取全量资源树(返回嵌套层次结构)** - `POST /api/resources/saveOrUpdate`:新增或编辑节点 - `POST /api/resources/delete`:删除节点 - `POST /api/resources/icon/upload`:图标上传 #### ResourceServiceImpl 实现完整的业务逻辑: - **层级约束验证**:确保父子关系的合法性,使用MenuType.isLegalChild()进行统一验证 - **字段必填校验**:根据不同类型验证必填字段 - **级联清理**:删除时自动清理角色授权引用 - **图标上传**:支持多种格式的图标文件上传 - **树形结构构建**:使用TreeUtils构建真正的层次结构 章节来源 - [ResourceController.java:1-56](file://crm-auth/src/main/java/com/crm/auth/controller/ResourceController.java#L1-56) ### 数据权限范围控制(DataScopeEnum 与拦截器) - 数据权限类型 - 全部数据、本部门数据、本部门及子部门数据、仅本人数据等 - 注解驱动 - 在方法上使用 @DataScope 指定数据范围与目标表 - 拦截与SQL改写 - DataScopeInterceptor 读取上下文中的数据权限范围 - DataScopeTables 维护表与列的映射关系 - 通过 MyBatis Plus 的 SQL 注入器自动追加 WHERE 条件 ```mermaid sequenceDiagram participant Controller as "业务控制器" participant Interceptor as "DataScopeInterceptor" participant Helper as "DataScopeHelper" participant Tables as "DataScopeTables" participant MP as "MyBatisPlus注入器" participant DB as "数据库" Controller->>Interceptor : "进入受保护方法" Interceptor->>Helper : "解析@DataScope参数" Helper->>Tables : "查找表/列映射" Tables-->>Helper : "返回映射信息" Helper-->>MP : "生成数据权限WHERE片段" MP-->>DB : "执行带限制的SQL" DB-->>Controller : "返回受限结果" ``` 章节来源 - [DataScopeEnum.java:1-19](file://crm-auth/src/main/java/com/crm/auth/domain/enums/DataScopeEnum.java#L1-L19) - [DataScope.java:1-200](file://crm-base/src/main/java/com/crm/base/annotation/DataScope.java#L1-L200) - [DataScopeInterceptor.java:1-200](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeInterceptor.java#L1-L200) - [DataScopeTables.java:1-200](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeTables.java#L1-L200) - [DataScopeHelper.java:1-200](file://crm-base/src/main/java/com/crm/base/security/DataScopeHelper.java#L1-L200) - [CrmSqlInjector.java:1-200](file://crm-base/src/main/java/com/crm/base/config/CrmSqlInjector.java#L1-L200) ### 认证与安全配置(SecurityConfig、JwtAuthenticationFilter、TokenService) - SecurityConfig:定义URL白名单、授权规则、跨域与异常处理器 - JwtAuthenticationFilter:解析JWT,填充认证上下文 - TokenService:生成、刷新、注销令牌,维护会话状态 ```mermaid classDiagram class SecurityConfig { +configure(http) void +cors() CorsConfigurationSource +exceptionHandler() SecurityExceptionHandlers } class JwtAuthenticationFilter { +doFilter(request, response, chain) void +parseToken(request) String +setContext(token) void } class TokenService { +createToken(user) String +refreshToken(token) String +logout(token) void +validate(token) boolean } SecurityConfig --> JwtAuthenticationFilter : "注册过滤器" JwtAuthenticationFilter --> TokenService : "验证/解析令牌" ``` 章节来源 - [SecurityConfig.java:1-200](file://crm-auth/src/main/java/com/crm/auth/config/SecurityConfig.java#L1-L200) - [JwtAuthenticationFilter.java:1-200](file://crm-auth/src/main/java/com/crm/auth/security/JwtAuthenticationFilter.java#L1-L200) - [TokenService.java:1-200](file://crm-auth/src/main/java/com/crm/auth/security/TokenService.java#L1-L200) ### 权限注解使用与最佳实践 - 接口级权限控制 - 在需要权限校验的方法上标注权限标识(如菜单code或按钮标识) - 结合白名单跳过敏感接口校验 - 数据权限注解 - 在查询方法上标注 @DataScope,指定范围类型与目标表 - 确保 DataScopeTables 中已配置对应表的列映射 - 注意事项 - 避免在事务内频繁切换数据权限上下文 - 合理设置缓存失效时机,保证权限变更后即时生效 **更新** 新的PermissionResolver接口提供了更清晰的权限解析契约,实现了fail-closed安全原则和更好的职责分离。 章节来源 - [DataScope.java:1-200](file://crm-base/src/main/java/com/crm/base/annotation/DataScope.java#L1-L200) - [DataScopeTables.java:1-200](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeTables.java#L1-L200) - [PermissionResolver.java:1-36](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolver.java#L1-36) ### 动态权限加载与缓存机制 - 动态加载 - 登录后根据用户角色拉取菜单树与按钮权限 - 将权限集合与菜单树写入缓存 - 缓存键设计 - 用户维度:user:{userId}:perms - 角色维度:role:{roleId}:menuTree - 缓存更新 - 角色/菜单变更触发失效 - 提供手动刷新接口供管理员使用 **更新** 新的PermissionResolverImpl实现了统一的查询链,通过DeptTreeCache优化部门树展开性能,提升了整体查询效率。 章节来源 - [PermissionResolverImpl.java:1-140](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolverImpl.java#L1-L140) - [DeptTreeCache.java:1-200](file://crm-auth/src/main/java/com/crm/auth/service/DeptTreeCache.java#L1-L200) ### 配置方法与初始化 - 权限配置 - PermissionConfig:集中管理权限相关开关与默认值 - 安全配置 - SecurityConfig:URL白名单、跨域、异常处理器 - 数据初始化 - DataInitializer:初始化默认角色、菜单、管理员账号等 **更新** DataInitializer现在支持三层资源层级结构的初始化,包括目录、菜单和按钮的完整权限体系。 章节来源 - [PermissionConfig.java:1-200](file://crm-auth/src/main/java/com/crm/auth/config/PermissionConfig.java#L1-L200) - [SecurityConfig.java:1-200](file://crm-auth/src/main/java/com/crm/auth/config/SecurityConfig.java#L1-L200) - [DataInitializer.java:1-76](file://crm-auth/src/main/java/com/crm/auth/config/DataInitializer.java#L1-L76) ### 路由路径处理逻辑改进 改进了路由路径处理逻辑,避免空字符串覆盖数据库值: - **非空值覆盖原则**:只有当node.getRoute()为非空时才覆盖entity.getPath() - **空串保留机制**:空字符串或空白字符不会覆盖数据库中已有的path值 - **编辑模式支持**:在编辑模式下,如果未提供route但数据库已有path则保持原值 这种改进确保了数据的一致性和完整性,避免了意外覆盖数据库中的有效数据。 章节来源 - [ResourceServiceImpl.java:239-242](file://crm-auth/src/main/java/com/crm/auth/service/impl/ResourceServiceImpl.java#L239-L242) ### API设计标准化 资源管理系统的API设计遵循全局接口契约,采用显式动作后缀模式: - **GET /api/resources/list**:**获取全量资源树,返回嵌套层次结构** - **POST /api/resources/saveOrUpdate**:新增或编辑节点,支持表单字段接收 - **POST /api/resources/delete**:删除节点,通过@RequestParam接收ID参数 - **POST /api/resources/icon/upload**:图标上传,支持MultipartFile文件处理 这种设计确保了与应用程序其他部分的API设计一致性,避免了传统RESTful约定的歧义。 章节来源 - [ResourceController.java:1-56](file://crm-auth/src/main/java/com/crm/auth/controller/ResourceController.java#L1-56) ### 树形结构构建机制 基于TreeUtils的高效树形结构构建机制: - **O(n)复杂度算法**:相比旧版O(n²)算法,性能显著提升 - **泛型支持**:支持Long/String等多种主键类型 - **灵活配置**:通过函数式接口支持自定义的getter/setter方法 - **智能分组**:按parentId分组后一次性挂载子节点 ```mermaid flowchart TD Start(["开始构建树"]) --> EmptyCheck{"列表是否为空?"} EmptyCheck --> |是| ReturnEmpty["返回空列表"] EmptyCheck --> |否| IdCollection["收集所有节点ID"] IdCollection --> GroupByParent["按parentId分组"] GroupByParent --> MountChildren["挂载子节点"] MountChildren --> IdentifyRoots["识别顶级节点"] IdentifyRoots --> ReturnTree["返回树形结构"] ``` 章节来源 - [TreeUtils.java:36-71](file://crm-base/src/main/java/com/crm/base/utils/TreeUtils.java#L36-L71) ### 角色管理服务的事务安全增强 **新增** 角色管理服务现在具有完整的事务保护机制: - **assignResources方法**:使用@Transactional注解确保角色-菜单关联操作的事务完整性 - **deleteRoleCascade方法**:级联删除操作在事务中执行,保证数据一致性 - **全量替换策略**:先删除后插入的方式确保角色权限的准确更新 ```mermaid flowchart TD Start(["角色分配开始"]) --> DeleteExisting["删除现有角色-菜单关联"] DeleteExisting --> CheckMenuIds{"菜单ID列表是否为空?"} CheckMenuIds --> |是| SkipInsert["跳过插入操作"] CheckMenuIds --> |否| InsertNew["批量插入新的角色-菜单关联"] SkipInsert --> Commit["提交事务"] InsertNew --> Commit Commit --> Success["操作成功"] ``` **更新** 通过@Service注解和@Transactional配置,所有角色相关的CRUD操作都具有事务保护,防止部分更新导致的数据不一致问题。 章节来源 - [SysRoleServiceImpl.java:30-42](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysRoleServiceImpl.java#L30-L42) - [SysRoleServiceImpl.java:105-122](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysRoleServiceImpl.java#L105-L122) - [SysRoleServiceImpl.java:124-142](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysRoleServiceImpl.java#L124-L142) - [ISysRoleService.java:9-42](file://crm-auth/src/main/java/com/crm/auth/service/ISysRoleService.java#L9-L42) ### 服务层整合与控制器简化 **新增** 控制器层现在完全通过Service层进行业务处理,消除了直接的Mapper访问: - **SystemController简化**:所有角色相关操作都通过ISysRoleService接口调用 - **职责分离**:控制器只负责参数处理和响应包装,业务逻辑集中在Service层 - **事务管理**:Service层统一管理事务边界,确保数据一致性 ```mermaid sequenceDiagram participant Client as "客户端" participant Controller as "SystemController" participant Service as "ISysRoleService" participant Impl as "SysRoleServiceImpl" participant DB as "数据库" Client->>Controller : "角色分配请求" Controller->>Service : "调用assignMenus方法" Service->>Impl : "执行事务方法" Impl->>DB : "删除现有关联" Impl->>DB : "插入新关联" DB-->>Impl : "返回操作结果" Impl-->>Service : "事务提交" Service-->>Controller : "返回成功响应" Controller-->>Client : "JSON响应" ``` **更新** 这种分层设计提升了代码的可维护性和测试性,同时确保了业务逻辑的集中管理和事务的一致性。 章节来源 - [SystemController.java:85-95](file://crm-auth/src/main/java/com/crm/auth/controller/SystemController.java#L85-L95) - [SysRoleServiceImpl.java:30-42](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysRoleServiceImpl.java#L30-L42) ## 依赖关系分析 - 模块依赖 - crm-auth 依赖 crm-base(异常、工具、数据可见性上下文) - crm-app 依赖 crm-auth(作为应用入口) - 组件耦合 - PermissionResolverImpl 依赖多个Mapper和DeptTreeCache - ResourceServiceImpl 依赖 ISysMenuService、FileApi - DataScopeInterceptor 依赖 DataScopeHelper 与 CrmSqlInjector - SecurityConfig 依赖 JwtAuthenticationFilter 与异常处理器 - **新增** SysRoleServiceImpl 依赖 SysRoleMenuMapper,通过事务管理确保数据一致性 ```mermaid graph LR APP["crm-app"] --> AUTH["crm-auth"] AUTH --> BASE["crm-base"] AUTH --> |"依赖"| Mapper["Mapper层"] AUTH --> |"依赖"| Service["Service层"] Service --> |"依赖"| Mapper ResourceController --> ResourceService ResourceService --> SysMenuService ResourceService --> FileApi PermissionResolverImpl --> DeptTreeCache PermissionResolverImpl --> MultipleMappers["多个Mapper"] SystemController --> ISysRoleService ISysRoleService --> SysRoleServiceImpl SysRoleServiceImpl --> SysRoleMenuMapper ``` 章节来源 - [CrmAppApplication.java:1-200](file://crm-app/src/main/java/com/crm/app/CrmAppApplication.java#L1-L200) - [AuthApplication.java:1-200](file://crm-auth/src/main/java/com/crm/auth/AuthApplication.java#L1-L200) - [PermissionResolverImpl.java:44-50](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolverImpl.java#L44-L50) - [SystemController.java:32-36](file://crm-auth/src/main/java/com/crm/auth/controller/SystemController.java#L32-L36) ## 性能考虑 - 缓存优先 - 菜单树与权限集合应缓存至Redis,降低重复查询 - 合理设置过期时间与失效策略 - 批量与懒加载 - 菜单树构建尽量使用批量查询与懒加载 - 数据权限SQL优化 - 在 DataScopeTables 中精确映射表与列,避免全表扫描 - 为常用过滤列添加索引 - **新增** 资源树操作优化 - TreeUtils提供O(n)复杂度的树构建算法,性能显著提升 - listAll()方法直接返回树形结构,减少前端处理开销 - 图标上传异步处理提升用户体验 - 使用MenuType枚举提高类型检查效率 - **新增** 权限解析优化 - 统一的查询链避免重复数据库访问 - DeptTreeCache缓存部门树结构 - LinkedHashSet保持权限码插入顺序,提升后续处理效率 - **新增** 事务优化 - 角色分配操作使用批量插入,减少数据库往返次数 - 事务边界明确,避免长事务影响系统性能 - **新增** 祖先补全优化 - 批量查询所有菜单数据,避免N+1查询问题 - 内存中构建ID→parentId映射,提升遍历效率 - 使用LinkedHashSet确保结果集的唯一性和顺序 **更新** 新的PermissionResolverImpl通过统一的查询链和缓存机制,显著减少了数据库访问次数。DeptTreeCache的使用进一步优化了部门树的展开性能。事务管理的优化确保了数据一致性的同时不影响系统性能。祖先补全机制的批量查询优化避免了N+1查询问题,提升了整体性能。 ## 故障排查指南 - 常见错误 - 未认证或令牌过期:检查 JwtAuthenticationFilter 与 TokenService 配置 - 权限不足:确认角色-菜单授权是否正确,缓存是否及时失效 - 数据权限不生效:检查 @DataScope 注解与 DataScopeTables 映射 - 资源树操作失败:检查层级约束验证和业务规则 - **新增** 角色分配失败:检查事务是否正常提交,菜单ID格式是否正确 - **新增** 内置角色操作失败:检查角色是否为builtin类型,操作是否符合保护规则 - **新增** 祖先补全失败:检查菜单数据完整性,是否存在循环引用 - 定位步骤 - 查看全局异常处理器输出 - 开启调试日志,观察拦截器与SQL注入过程 - 核对缓存键与失效时机 - 检查ResourceServiceImpl中的业务规则验证逻辑 - 验证MenuType枚举的正确使用 - 确认API端点是否符合标准化设计 - 检查listAll()方法返回的树形结构是否正确 - **新增** 检查SysRoleServiceImpl中的事务执行情况 - **新增** 验证Service层方法的调用链是否正确 - **新增** 检查@PreAuthorize注解的配置是否正确 - **新增** 验证祖先补全算法的正确性 - **新增** 事务相关问题排查 - 检查@Transactional注解是否正确配置 - 确认异常类型是否触发事务回滚 - 验证数据库连接池配置是否合理 - 检查是否有长事务影响系统性能 - **新增** 权限注解相关问题排查 - 检查@PreAuthorize注解的权限码是否正确配置 - 确认用户是否拥有相应的权限码 - 验证权限码的命名规范是否符合要求 - **新增** 角色验证相关问题排查 - 检查数据范围枚举值的合法性 - 验证内置角色保护逻辑的正确性 - 确认角色编码唯一性校验是否正常工作 **更新** 对于事务相关问题,建议特别关注SysRoleServiceImpl中的事务配置和异常处理。新的事务保护机制应该能够正确处理各种异常情况,确保数据的完整性和一致性。@PreAuthorize注解的使用需要提供正确的权限码配置。祖先补全机制的故障通常与菜单数据完整性有关,需要检查是否存在循环引用或数据缺失。 章节来源 - [GlobalExceptionHandlerAdvice.java:1-200](file://crm-base/src/main/java/com/crm/base/advice/GlobalExceptionHandlerAdvice.java#L1-L200) - [JwtAuthenticationFilter.java:1-200](file://crm-auth/src/main/java/com/crm/auth/security/JwtAuthenticationFilter.java#L1-L200) - [TokenService.java:1-200](file://crm-auth/src/main/java/com/crm/auth/security/TokenService.java#L1-L200) - [DataScopeInterceptor.java:1-200](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeInterceptor.java#L1-L200) - [DataScopeTables.java:1-200](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeTables.java#L1-L200) - [ResourceServiceImpl.java:1-265](file://crm-auth/src/main/java/com/crm/auth/service/impl/ResourceServiceImpl.java#L1-L265) - [PermissionResolverImpl.java:1-140](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolverImpl.java#L1-L140) - [SysRoleServiceImpl.java:30-42](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysRoleServiceImpl.java#L30-L42) - [RoleController.java:32-96](file://crm-auth/src/main/java/com/crm/auth/controller/RoleController.java#L32-L96) - [SysMenuServiceImpl.java:17-41](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysMenuServiceImpl.java#L17-L41) ## 结论 本权限管理系统以RBAC为核心,结合注解驱动的数据权限控制与拦截器实现的SQL改写,形成完整的权限校验与数据隔离方案。**通过本次重大架构重构,系统实现了从单体PermissionServiceImpl到模块化PermissionResolver接口与PermissionGrant值对象的转变,采用了fail-closed安全原则和更好的职责分离设计。** **最重要的改进是新的权限解析引擎架构**:PermissionResolver接口提供了清晰的权限解析契约,PermissionGrant作为不可变的值对象封装了完整的权限信息,PermissionResolverImpl实现了统一的「用户 → 角色 → 授权 → 资源」查询链,显著提升了性能和可维护性。同时,系统保持了完整的三层资源层级结构(目录-菜单-按钮),SysMenu实体的增强功能和ResourceNode DTO的双向转换能力显著提升了权限控制的精细度和灵活性。新增的统一资源树管理系统提供了完善的CRUD操作接口,支持严格的层级约束验证和图标上传功能,并且API设计遵循全局接口契约,确保了一致性。 **最新的改进重点是增强的角色管理系统和祖先补全机制**:SysRoleServiceImpl现在具备完整的角色验证逻辑,包括数据范围限制、内置角色保护和编码唯一性校验。祖先补全机制通过批量查询和内存遍历算法,高效地计算并补全菜单ID的祖先节点,确保层级权限的正确继承。所有角色相关操作都配备了完整的事务保护机制,确保数据一致性和原子性。RoleController集成了全面的OpenAPI注解,提供完整的API文档支持。细粒度的@PreAuthorize权限控制使得每个接口都可以独立配置权限要求。 通过对PermissionResolverImpl的重构,使用了统一的查询链避免重复数据库访问,通过DeptTreeCache优化了部门树展开性能,通过LinkedHashSet保证了权限码的顺序性。新的fail-closed安全原则确保了系统的健壮性,任何解析失败都会抛出异常而不是返回部分成功的状态。 **最重要的改进是新的权限解析引擎架构**:PermissionResolver接口提供了清晰的权限解析契约,PermissionGrant作为不可变的值对象封装了完整的权限信息,PermissionResolverImpl实现了统一的「用户 → 角色 → 授权 → 资源」查询链,显著提升了性能和可维护性。同时,系统保持了完整的三层资源层级结构(目录-菜单-按钮),SysMenu实体的增强功能和ResourceNode DTO的双向转换能力显著提升了权限控制的精细度和灵活性。新增的统一资源树管理系统提供了完善的CRUD操作接口,支持严格的层级约束验证和图标上传功能,并且API设计遵循全局接口契约,确保了一致性。 **最新的改进重点是增强的角色管理系统和祖先补全机制**:SysRoleServiceImpl现在具备完整的角色验证逻辑,包括数据范围限制、内置角色保护和编码唯一性校验。祖先补全机制通过批量查询和内存遍历算法,高效地计算并补全菜单ID的祖先节点,确保层级权限的正确继承。所有角色相关操作都配备了完整的事务保护机制,确保数据一致性和原子性。RoleController集成了全面的OpenAPI注解,提供完整的API文档支持。细粒度的@PreAuthorize权限控制使得每个接口都可以独立配置权限要求。 通过对PermissionResolverImpl的重构,使用了统一的查询链避免重复数据库访问,通过DeptTreeCache优化了部门树展开性能,通过LinkedHashSet保证了权限码的顺序性。新的fail-closed安全原则确保了系统的健壮性,任何解析失败都会抛出异常而不是返回部分成功的状态。 ## 附录 - 术语 - RBAC:基于角色的访问控制 - 数据权限:基于用户所属组织或范围的查询限制 - fail-closed:失败关闭的安全原则,解析失败即拒绝访问 - @PreAuthorize:Spring Security的预授权注解,用于细粒度权限控制 - 祖先补全:层级权限体系中自动补全父级节点的过程 - 内置角色:系统预定义的核心角色,受到特殊保护 - OpenAPI:API文档规范和注解,用于自动生成API文档 - 参考 - 实体与枚举:SysRole、SysMenu、DataScopeEnum、MenuType - 数据传输对象:ResourceNode、RoleDetailVO - **新增** 权限解析引擎:PermissionResolver、PermissionGrant、PermissionResolverImpl - 服务与拦截:DataScopeInterceptor - **新增** 资源管理:ResourceController、ResourceServiceImpl、IResourceService - **新增** 工具类:TreeUtils - 配置与初始化:PermissionConfig、SecurityConfig、DataInitializer - **新增** 角色管理:SysRoleServiceImpl、ISysRoleService、RoleController - **新增** 常量定义:AuthConstants **更新** 重点关注新的PermissionResolver接口与PermissionGrant值对象的设计,它们提供了更好的职责分离和fail-closed安全原则。PermissionResolverImpl的统一查询链和DeptTreeCache缓存机制显著提升了性能。新增的统一资源树管理系统完善了权限管理的CRUD操作,并通过MenuType枚举确保了类型安全性和代码一致性。API设计的标准化确保了与全局接口契约的一致性。**特别重要的是,增强的角色管理系统、祖先补全机制、事务安全保障和OpenAPI文档注解的引入,大幅提升了系统的安全性、可维护性和开发效率。**