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.
 
 
 
 
 

41 KiB

权限管理系统

**本文引用的文件** - [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:文件服务(与本权限文档无直接关联)
graph TB
subgraph "应用层"
APP["crm-app<br/>启动与应用配置"]
end
subgraph "认证与权限"
AUTH["crm-auth<br/>RBAC实体/服务/安全/客户端"]
end
subgraph "基础能力"
BASE["crm-base<br/>异常/工具/通用配置/数据可见性"]
end
APP --> AUTH
AUTH --> BASE

章节来源

  • CrmAppApplication.java:1-200
  • AuthApplication.java:1-200

核心组件

  • 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
  • ISysRoleService.java:9-42
  • RoleController.java:25-30
  • ResourceController.java:22
  • PermissionResolver.java:1-36
  • PermissionGrant.java:1-68
  • PermissionResolverImpl.java:1-140

架构总览

下图展示重构后的权限系统在请求链路中的关键交互:从JWT鉴权到权限解析,再到数据可见性注入与SQL改写。

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
  • JwtAuthenticationFilter.java:1-200
  • PermissionResolver.java:1-36
  • PermissionGrant.java:1-68
  • PermissionResolverImpl.java:1-140

详细组件分析

增强的角色管理系统与验证逻辑

新增 SysRoleServiceImpl实现了完整的角色验证逻辑,包含多层次的安全检查和业务规则:

  • 基础非空校验:角色名称和编码必填验证
  • 数据范围限制:禁止使用CUSTOM自定义数据范围,只允许预定义的范围类型
  • 内置角色保护
    • 创建保护:不允许通过接口创建builtin=true的角色
    • 修改保护:内置角色的roleCode不可修改
    • 删除保护:内置角色不允许删除
  • 编码唯一性校验:确保角色编码的全局唯一性
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

祖先补全机制优化

新增 系统实现了高效的祖先补全机制,确保层级权限的正确继承:

  • 批量查询优化:一次性获取所有菜单数据,构建ID→parentId映射
  • 内存遍历算法:在内存中向上遍历父节点,避免多次数据库查询
  • 去重处理:使用LinkedHashSet确保结果集的唯一性和插入顺序
  • 循环检测:防止因数据异常导致的无限循环
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

事务安全全面增强

新增 所有角色相关操作都配备了完整的事务保护机制:

  • assignResources方法:使用@Transactional注解确保角色-菜单关联操作的事务完整性
  • deleteRoleCascade方法:级联删除操作在事务中执行,保证数据一致性
  • 异常回滚:任何异常都会触发事务回滚,确保数据的一致性
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
  • SysRoleServiceImpl.java:124-142

OpenAPI文档注解完善

新增 RoleController集成了全面的OpenAPI注解,提供完整的API文档支持:

  • @Operation注解:每个接口都有详细的描述和标签分类
  • 参数说明:所有请求参数都有清晰的说明文档
  • 响应类型:明确的返回值类型定义
  • 标签分组:按功能模块对API进行分类管理
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

细粒度权限控制与@PreAuthorize注解使用

新增 系统现已全面支持基于@PreAuthorize注解的细粒度权限控制,从粗粒度的角色检查演进为精确到按钮级别的权限管理:

  • RoleController权限控制:每个接口都使用@PreAuthorize注解指定具体的权限码
    • hasAuthority('crm:role:list'):角色列表查询权限
    • hasAuthority('crm:role:save'):角色保存权限
    • hasAuthority('crm:role:detail'):角色详情查看权限
    • hasAuthority('crm:role:assign'):角色权限分配权限
    • hasAuthority('crm:role:delete'):角色删除权限
  • 权限码标准化:采用模块:功能:操作的命名规范,确保权限码的一致性和可读性
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

三层资源层级结构设计

系统现在支持完整的三层资源层级结构,通过MenuType枚举定义了目录、菜单、按钮三种资源类型:

  • 目录(CATALOG):作为收纳容器,不承载页面,只能挂menu子节点
  • 菜单(MENU):可导航的页面,只能挂button子节点
  • 按钮(BUTTON):叶子节点,不可再挂子节点,承载权限码和接口映射
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
  • SysMenu.java:12-76
  • ResourceNode.java:16-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

数据权限范围控制(DataScopeEnum 与拦截器)

  • 数据权限类型
    • 全部数据、本部门数据、本部门及子部门数据、仅本人数据等
  • 注解驱动
    • 在方法上使用 @DataScope 指定数据范围与目标表
  • 拦截与SQL改写
    • DataScopeInterceptor 读取上下文中的数据权限范围
    • DataScopeTables 维护表与列的映射关系
    • 通过 MyBatis Plus 的 SQL 注入器自动追加 WHERE 条件
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
  • DataScope.java:1-200
  • DataScopeInterceptor.java:1-200
  • DataScopeTables.java:1-200
  • DataScopeHelper.java:1-200
  • CrmSqlInjector.java:1-200

认证与安全配置(SecurityConfig、JwtAuthenticationFilter、TokenService)

  • SecurityConfig:定义URL白名单、授权规则、跨域与异常处理器
  • JwtAuthenticationFilter:解析JWT,填充认证上下文
  • TokenService:生成、刷新、注销令牌,维护会话状态
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
  • JwtAuthenticationFilter.java:1-200
  • TokenService.java:1-200

权限注解使用与最佳实践

  • 接口级权限控制
    • 在需要权限校验的方法上标注权限标识(如菜单code或按钮标识)
    • 结合白名单跳过敏感接口校验
  • 数据权限注解
    • 在查询方法上标注 @DataScope,指定范围类型与目标表
    • 确保 DataScopeTables 中已配置对应表的列映射
  • 注意事项
    • 避免在事务内频繁切换数据权限上下文
    • 合理设置缓存失效时机,保证权限变更后即时生效

更新 新的PermissionResolver接口提供了更清晰的权限解析契约,实现了fail-closed安全原则和更好的职责分离。

章节来源

  • DataScope.java:1-200
  • DataScopeTables.java:1-200
  • PermissionResolver.java:1-36

动态权限加载与缓存机制

  • 动态加载
    • 登录后根据用户角色拉取菜单树与按钮权限
    • 将权限集合与菜单树写入缓存
  • 缓存键设计
    • 用户维度:user:{userId}:perms
    • 角色维度:role:{roleId}:menuTree
  • 缓存更新
    • 角色/菜单变更触发失效
    • 提供手动刷新接口供管理员使用

更新 新的PermissionResolverImpl实现了统一的查询链,通过DeptTreeCache优化部门树展开性能,提升了整体查询效率。

章节来源

  • PermissionResolverImpl.java:1-140
  • DeptTreeCache.java:1-200

配置方法与初始化

  • 权限配置
    • PermissionConfig:集中管理权限相关开关与默认值
  • 安全配置
    • SecurityConfig:URL白名单、跨域、异常处理器
  • 数据初始化
    • DataInitializer:初始化默认角色、菜单、管理员账号等

更新 DataInitializer现在支持三层资源层级结构的初始化,包括目录、菜单和按钮的完整权限体系。

章节来源

  • PermissionConfig.java:1-200
  • SecurityConfig.java:1-200
  • DataInitializer.java:1-76

路由路径处理逻辑改进

改进了路由路径处理逻辑,避免空字符串覆盖数据库值:

  • 非空值覆盖原则:只有当node.getRoute()为非空时才覆盖entity.getPath()
  • 空串保留机制:空字符串或空白字符不会覆盖数据库中已有的path值
  • 编辑模式支持:在编辑模式下,如果未提供route但数据库已有path则保持原值

这种改进确保了数据的一致性和完整性,避免了意外覆盖数据库中的有效数据。

章节来源

  • ResourceServiceImpl.java:239-242

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

树形结构构建机制

基于TreeUtils的高效树形结构构建机制:

  • O(n)复杂度算法:相比旧版O(n²)算法,性能显著提升
  • 泛型支持:支持Long/String等多种主键类型
  • 灵活配置:通过函数式接口支持自定义的getter/setter方法
  • 智能分组:按parentId分组后一次性挂载子节点
flowchart TD
Start(["开始构建树"]) --> EmptyCheck{"列表是否为空?"}
EmptyCheck --> |是| ReturnEmpty["返回空列表"]
EmptyCheck --> |否| IdCollection["收集所有节点ID"]
IdCollection --> GroupByParent["按parentId分组"]
GroupByParent --> MountChildren["挂载子节点"]
MountChildren --> IdentifyRoots["识别顶级节点"]
IdentifyRoots --> ReturnTree["返回树形结构"]

章节来源

  • TreeUtils.java:36-71

角色管理服务的事务安全增强

新增 角色管理服务现在具有完整的事务保护机制:

  • assignResources方法:使用@Transactional注解确保角色-菜单关联操作的事务完整性
  • deleteRoleCascade方法:级联删除操作在事务中执行,保证数据一致性
  • 全量替换策略:先删除后插入的方式确保角色权限的准确更新
flowchart TD
Start(["角色分配开始"]) --> DeleteExisting["删除现有角色-菜单关联"]
DeleteExisting --> CheckMenuIds{"菜单ID列表是否为空?"}
CheckMenuIds --> |是| SkipInsert["跳过插入操作"]
CheckMenuIds --> |否| InsertNew["批量插入新的角色-菜单关联"]
SkipInsert --> Commit["提交事务"]
InsertNew --> Commit
Commit --> Success["操作成功"]

更新 通过@Service注解和@Transactional配置,所有角色相关的CRUD操作都具有事务保护,防止部分更新导致的数据不一致问题。

章节来源

  • SysRoleServiceImpl.java:30-42
  • SysRoleServiceImpl.java:105-122
  • SysRoleServiceImpl.java:124-142
  • ISysRoleService.java:9-42

服务层整合与控制器简化

新增 控制器层现在完全通过Service层进行业务处理,消除了直接的Mapper访问:

  • SystemController简化:所有角色相关操作都通过ISysRoleService接口调用
  • 职责分离:控制器只负责参数处理和响应包装,业务逻辑集中在Service层
  • 事务管理:Service层统一管理事务边界,确保数据一致性
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
  • SysRoleServiceImpl.java:30-42

依赖关系分析

  • 模块依赖
    • crm-auth 依赖 crm-base(异常、工具、数据可见性上下文)
    • crm-app 依赖 crm-auth(作为应用入口)
  • 组件耦合
    • PermissionResolverImpl 依赖多个Mapper和DeptTreeCache
    • ResourceServiceImpl 依赖 ISysMenuService、FileApi
    • DataScopeInterceptor 依赖 DataScopeHelper 与 CrmSqlInjector
    • SecurityConfig 依赖 JwtAuthenticationFilter 与异常处理器
    • 新增 SysRoleServiceImpl 依赖 SysRoleMenuMapper,通过事务管理确保数据一致性
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
  • AuthApplication.java:1-200
  • PermissionResolverImpl.java:44-50
  • SystemController.java:32-36

性能考虑

  • 缓存优先
    • 菜单树与权限集合应缓存至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
  • JwtAuthenticationFilter.java:1-200
  • TokenService.java:1-200
  • DataScopeInterceptor.java:1-200
  • DataScopeTables.java:1-200
  • ResourceServiceImpl.java:1-265
  • PermissionResolverImpl.java:1-140
  • SysRoleServiceImpl.java:30-42
  • RoleController.java:32-96
  • SysMenuServiceImpl.java:17-41

结论

本权限管理系统以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文档注解的引入,大幅提升了系统的安全性、可维护性和开发效率。