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.

834 lines
44 KiB

1 month ago
# 权限管理系统
<cite>
**本文引用的文件**
- [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)
- [JwtAuthenticationFilter.java](file://crm-auth/src/main/java/com/crm/auth/security/JwtAuthenticationFilter.java)
1 month ago
- [SystemController.java](file://crm-auth/src/main/java/com/crm/auth/controller/SystemController.java)
- [SysMenu.java](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysMenu.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)
1 month ago
- [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)
- [ApiPermissionInterceptor.java](file://crm-auth/src/main/java/com/crm/auth/security/ApiPermissionInterceptor.java)
- [ApiPermissionCache.java](file://crm-auth/src/main/java/com/crm/auth/security/ApiPermissionCache.java)
- [ApiPermissionRule.java](file://crm-auth/src/main/java/com/crm/auth/security/ApiPermissionRule.java)
- [WebMvcConfig.java](file://crm-auth/src/main/java/com/crm/auth/config/WebMvcConfig.java)
- [AuthServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/AuthServiceImpl.java)
- [ResourceServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/ResourceServiceImpl.java)
1 month ago
</cite>
1 month ago
## 更新摘要
**所做更改**
- **新增** 动态API权限拦截系统,基于Caffeine缓存和HandlerInterceptor实现URL级别的权限控制
- **增强** AuthServiceImpl认证流程重构,优化事务处理和第三方登录逻辑
- **完善** 资源树变更时的缓存失效机制,确保权限规则实时更新
- **扩展** 测试覆盖范围,包含API权限拦截、认证流程和数据权限的完整测试场景
1 month ago
1 month ago
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考虑](#性能考虑)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)
## 简介
本文件为基于RBAC(角色-资源)的权限管理系统文档,覆盖角色管理、菜单权限控制与数据权限范围控制。重点说明实体设计(如 SysRole、SysMenu)、权限校验逻辑(PermissionResolver三组件架构)、数据权限类型(DataScopeEnum),以及权限注解使用、动态权限加载与权限缓存机制的实现细节和配置方法。读者可据此快速理解系统权限模型并正确扩展与使用。
1 month ago
**更新** 本次更新重点关注新增的动态API权限拦截系统和改进的认证流程重构,包括ApiPermissionInterceptor、ApiPermissionCache等核心组件,以及AuthServiceImpl的事务处理优化。
1 month ago
1 month ago
## 项目结构
本项目采用多模块组织:
- crm-app:应用启动入口与全局配置
- crm-auth:认证与权限核心模块,包含RBAC实体、服务、安全拦截、第三方登录等
- crm-base:公共基础能力(异常、工具、通用配置、数据可见性上下文等)
- crm-file:文件服务(与本权限文档无直接关联)
```mermaid
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](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:增强的菜单与按钮资源定义,支持三层层级结构(目录-菜单-按钮)和细粒度权限控制
1 month ago
- SysUserRole、SysRoleMenu:用户-角色、角色-菜单的多对多关系表
- SysDept、SysUserDept:部门与用户部门关系,用于数据权限范围
- 数据传输对象
- ResourceNode:支持SysMenu与ResourceNode之间的双向转换,包含children字段支持层次结构
- 权限解析引擎(**重构**)
- **PermissionResolver接口**:定义权限解析的核心抽象,包含resolve()和visibleMenuTree()两个方法
- **PermissionGrant值对象**:不可变的权限解析结果,包含数据可见性、权限码并集和角色编码
- **PermissionResolverImpl实现**:具体的权限解析逻辑实现,采用共享查询链优化
- **动态API权限拦截系统(新增)**
- **ApiPermissionInterceptor**:HandlerInterceptor实现,基于AntPathMatcher进行URL模式匹配
- **ApiPermissionCache**:基于Caffeine的进程内缓存,懒加载已注册的API权限规则
- **ApiPermissionRule**:记录apiUrl pattern与perms权限码的映射关系
- 控制器层
- ResourceController:统一权限资源树管理端接口
- SystemController:系统管理相关接口,集成新的权限解析器
1 month ago
- 安全与拦截
- SecurityConfig、JwtAuthenticationFilter:认证流程与JWT过滤,集成新的权限解析器
1 month ago
- DataScopeInterceptor、DataScopeTables:数据权限拦截与SQL改写
- AuthLoginUser、TokenService:当前登录用户上下文与令牌操作
- 数据权限
- DataScopeEnum:数据权限范围枚举(如全部、本部门、本部门及子部门、仅本人等)
- DataScope(注解)、DataScopeHelper、DataVisibilityContext:注解驱动的数据可见性控制
**更新** 权限解析引擎已重构为三组件架构,PermissionResolver接口定义了清晰的权限解析契约,PermissionGrant提供了不可变的权限结果封装,PermissionResolverImpl实现了高效的权限解析逻辑。新增的动态API权限拦截系统通过ApiPermissionInterceptor和ApiPermissionCache实现了URL级别的权限控制。SystemController现在直接使用PermissionResolver进行菜单树获取,简化了调用方式。
1 month ago
1 month ago
章节来源
- [SysRole.java:1-200](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysRole.java#L1-L200)
- [SysMenu.java:12-76](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysMenu.java#L12-L76)
- [ResourceNode.java:16-84](file://crm-auth/src/main/java/com/crm/auth/domain/dto/ResourceNode.java#L16-L84)
- [PermissionResolver.java:16-35](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolver.java#L16-L35)
- [PermissionGrant.java:23-67](file://crm-auth/src/main/java/com/crm/auth/security/PermissionGrant.java#L23-L67)
- [PermissionResolverImpl.java:42-139](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolverImpl.java#L42-L139)
- [ApiPermissionInterceptor.java:32-82](file://crm-auth/src/main/java/com/crm/auth/security/ApiPermissionInterceptor.java#L32-L82)
- [ApiPermissionCache.java:25-65](file://crm-auth/src/main/java/com/crm/auth/security/ApiPermissionCache.java#L25-L65)
- [SystemController.java:36-44](file://crm-auth/src/main/java/com/crm/auth/controller/SystemController.java#L36-L44)
1 month ago
## 架构总览
下图展示认证与权限在请求链路中的关键交互:从JWT鉴权到权限校验、再到数据权限注入与SQL改写,以及新增的动态API权限拦截。
1 month ago
```mermaid
sequenceDiagram
participant Client as "客户端"
participant Filter as "JwtAuthenticationFilter"
participant Interceptor as "ApiPermissionInterceptor"
participant Resolver as "PermissionResolver"
participant Grant as "PermissionGrant"
participant Controller as "SystemController"
1 month ago
participant DB as "数据库"
Client->>Filter : "HTTP 请求 (带JWT)"
Filter->>Filter : "验证Token"
Filter->>Interceptor : "API权限拦截检查"
Interceptor->>Cache : "获取API权限规则"
Cache-->>Interceptor : "返回规则列表"
Interceptor->>Interceptor : "AntPathMatcher匹配"
Interceptor-->>Filter : "权限检查通过"
Filter->>Resolver : "调用权限解析器"
Resolver->>DB : "查询用户角色和权限"
DB-->>Resolver : "返回权限数据"
Resolver-->>Filter : "返回PermissionGrant"
Filter->>Filter : "设置Security上下文"
Controller->>Resolver : "获取菜单树"
Resolver->>DB : "查询可见菜单"
DB-->>Resolver : "返回菜单数据"
Resolver-->>Controller : "返回菜单树"
Controller-->>Client : "响应菜单数据"
1 month ago
```
**更新** 新的架构中,JwtAuthenticationFilter直接使用PermissionResolver进行权限解析,通过PermissionGrant封装完整的权限信息。新增的ApiPermissionInterceptor在JWT过滤器之后执行,提供URL级别的权限控制。SystemController也直接使用PermissionResolver获取菜单树,简化了调用链路。
1 month ago
1 month ago
图表来源
- [SecurityConfig.java:1-200](file://crm-auth/src/main/java/com/crm/auth/config/SecurityConfig.java#L1-L200)
- [JwtAuthenticationFilter.java:32-56](file://crm-auth/src/main/java/com/crm/auth/security/JwtAuthenticationFilter.java#L32-L56)
- [ApiPermissionInterceptor.java:38-80](file://crm-auth/src/main/java/com/crm/auth/security/ApiPermissionInterceptor.java#L38-L80)
- [PermissionResolver.java:16-35](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolver.java#L16-L35)
- [SystemController.java:40-44](file://crm-auth/src/main/java/com/crm/auth/controller/SystemController.java#L40-L44)
1 month ago
## 详细组件分析
### 权限解析三组件架构
**重构** 权限解析引擎已重构为清晰的三组件架构:
#### PermissionResolver接口
定义了权限解析的核心抽象:
- `resolve(Long userId)`:解析用户的数据可见性与全部授权码
- `visibleMenuTree(Long userId)`:获取用户可见的菜单树
#### PermissionGrant值对象
不可变的权限解析结果封装:
- `DataVisibility visibility`:数据可见性信息
- `Set<String> permCodes`:权限码并集(button节点且status=enabled)
- `Set<String> roleCodes`:角色编码集合
- `asAuthorities()`:合成Spring Security authorities
#### PermissionResolverImpl实现
具体的权限解析逻辑实现:
- 共享查询链:用户→角色→授权→资源
- 多角色权限合并:取最宽档可见性
- 权限码并集:仅包含button节点且启用状态的perms
- 菜单树构建:过滤button节点并按sort排序
1 month ago
```mermaid
classDiagram
class PermissionResolver {
+resolve(userId) PermissionGrant
+visibleMenuTree(userId) SysMenu[]
1 month ago
}
class PermissionGrant {
+DataVisibility visibility
+Set~String~ permCodes
+Set~String~ roleCodes
+asAuthorities() SimpleGrantedAuthority[]
1 month ago
}
class PermissionResolverImpl {
-SysUserRoleMapper sysUserRoleMapper
-SysRoleMapper sysRoleMapper
-SysRoleMenuMapper sysRoleMenuMapper
-SysMenuMapper sysMenuMapper
-AuthUserMapper authUserMapper
-DeptTreeCache deptTreeCache
-SysUserDeptMapper sysUserDeptMapper
+resolve(userId) PermissionGrant
+visibleMenuTree(userId) SysMenu[]
1 month ago
}
PermissionResolver <|.. PermissionResolverImpl
PermissionResolverImpl --> PermissionGrant : 返回
```
**更新** 新的三组件架构提供了清晰的职责分离,PermissionResolver接口定义了明确的契约,PermissionGrant作为不可变值对象确保数据安全,PermissionResolverImpl专注于权限解析逻辑的实现。
图表来源
- [PermissionResolver.java:16-35](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolver.java#L16-L35)
- [PermissionGrant.java:23-67](file://crm-auth/src/main/java/com/crm/auth/security/PermissionGrant.java#L23-L67)
- [PermissionResolverImpl.java:42-139](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolverImpl.java#L42-L139)
### 动态API权限拦截系统(新增)
**新增** 动态API权限拦截系统基于HandlerInterceptor实现URL级别的权限控制:
#### ApiPermissionInterceptor
HandlerInterceptor实现,负责URL模式匹配和权限校验:
- **fail-open策略**:未匹配任何注册规则时放行请求
- **AntPathMatcher匹配**:支持*单层通配和**多层通配
- **权限检查**:从SecurityContext读取用户authority集合进行匹配
- **403响应**:匹配到规则但用户无对应权限时返回403
#### ApiPermissionCache
基于Caffeine的进程内缓存,懒加载API权限规则:
- **单key缓存**:存储整份规则列表,避免频繁重建
- **懒加载机制**:首次访问时从数据库加载已启用的button节点
- **主动失效**:资源树变更后调用invalidate()清空缓存
- **规则过滤**:仅加载menuType=BUTTON且status='enabled'且有apiUrl的节点
#### ApiPermissionRule
简单的record类,记录API权限规则映射:
- **pattern**:Ant风格的URL模式
- **perms**:对应的权限码
```mermaid
flowchart TD
Start(["HTTP请求进入"]) --> GetRules["从缓存获取规则"]
GetRules --> MatchCheck{"是否有匹配规则?"}
MatchCheck --> |否| Pass["放行请求"]
MatchCheck --> |是| CheckPerm["检查用户权限"]
CheckPerm --> HasPerm{"用户有权限?"}
HasPerm --> |是| Pass
HasPerm --> |否| Deny["返回403"]
Pass --> End(["继续处理"])
Deny --> End
```
**更新** 动态API权限拦截系统提供了灵活的URL级别权限控制,通过Caffeine缓存保证性能,fail-open策略确保向后兼容性。
图表来源
- [ApiPermissionInterceptor.java:38-80](file://crm-auth/src/main/java/com/crm/auth/security/ApiPermissionInterceptor.java#L38-L80)
- [ApiPermissionCache.java:37-63](file://crm-auth/src/main/java/com/crm/auth/security/ApiPermissionCache.java#L37-L63)
- [ApiPermissionRule.java:9](file://crm-auth/src/main/java/com/crm/auth/security/ApiPermissionRule.java#L9)
### WebMvcConfig拦截器注册
**新增** WebMvcConfig配置类负责注册API权限拦截器:
- **拦截器注册**:将ApiPermissionInterceptor添加到MVC拦截器链
- **路径匹配**:仅拦截/api/**路径的请求
- **执行顺序**:在Spring Security(JWT过滤器)之后、Controller之前执行
```mermaid
flowchart TD
Start(["请求进入"]) --> JwtFilter["JWT过滤器"]
JwtFilter --> ApiInterceptor["API权限拦截器"]
ApiInterceptor --> Controller["业务控制器"]
Controller --> Response["返回响应"]
```
**更新** 拦截器的注册确保了权限检查的执行顺序,先进行JWT认证,再进行API权限检查,最后执行业务逻辑。
图表来源
- [WebMvcConfig.java:19-23](file://crm-auth/src/main/java/com/crm/auth/config/WebMvcConfig.java#L19-L23)
### JwtAuthenticationFilter集成新架构
**更新** JwtAuthenticationFilter已集成新的PermissionResolver:
- **fail-closed安全原则**:权限解析失败即拒绝请求
- **一次解析完成**:通过PermissionResolver.resolve()一次性获取所有权限信息
- **自动上下文装载**:将DataVisibility装载到DataVisibilityContext
- **Spring Security集成**:通过PermissionGrant.asAuthorities()生成authorities
```mermaid
flowchart TD
Start(["进入过滤器"]) --> TokenCheck{"Token有效?"}
TokenCheck --> |否| Next["继续过滤器链"]
TokenCheck --> |是| ResolvePerm["调用PermissionResolver.resolve()"]
ResolvePerm --> LoadContext["装载DataVisibility到上下文"]
LoadContext --> CreateAuth["创建UsernamePasswordAuthenticationToken"]
CreateAuth --> SetContext["设置到SecurityContextHolder"]
SetContext --> Next
Next --> End(["结束"])
```
**更新** 新的实现遵循fail-closed原则,权限解析失败时直接让请求失败,不存在部分成功的状态。通过PermissionGrant统一处理权限码和角色编码,简化了Spring Security的集成。
图表来源
- [JwtAuthenticationFilter.java:32-56](file://crm-auth/src/main/java/com/crm/auth/security/JwtAuthenticationFilter.java#L32-L56)
### SystemController集成新架构
**更新** SystemController已集成新的PermissionResolver:
- **菜单树获取**:通过permissionResolver.visibleMenuTree(userId)直接获取菜单树
- **简化调用**:无需复杂的Service层调用,直接通过接口获取数据
- **类型安全**:返回类型为List<SysMenu>,保证类型安全
```mermaid
flowchart TD
Start(["菜单树请求"]) --> GetUserId["获取当前用户ID"]
GetUserId --> CallResolver["调用PermissionResolver.visibleMenuTree()"]
CallResolver --> QueryRoles["查询用户角色"]
QueryRoles --> QueryMenus["查询角色授权的菜单"]
QueryMenus --> FilterVisible["过滤可见菜单"]
FilterVisible --> BuildTree["构建菜单树"]
BuildTree --> Return["返回菜单树"]
```
**更新** SystemController现在直接使用PermissionResolver接口,简化了菜单树的获取逻辑,提高了代码的可维护性和测试性。
图表来源
- [SystemController.java:40-44](file://crm-auth/src/main/java/com/crm/auth/controller/SystemController.java#L40-L44)
### 认证流程重构(AuthServiceImpl)
**更新** AuthServiceImpl进行了重大重构,优化了第三方登录流程和事务处理:
#### 主要改进
- **事务分离**:DB写入在事务中完成,Redis token写入在事务外执行,避免脏数据问题
- **组织准入预校验**:仅在首登注册前触发钉钉组织通讯录校验,减少HTTP调用开销
- **身份定位优化**:统一的locateUser方法供只读探测和登录定位共用,避免逻辑漂移
- **孤儿身份处理**:自动重定向指向已删除用户的身份绑定到新注册用户
#### 登录流程
1. **前置校验**:验证authCode非空
2. **三方用户信息获取**:通过clientFactory获取对应平台的用户信息
3. **组织准入预校验**:仅本地无匹配用户时触发
4. **事务内登录逻辑**:定位用户 + 校验状态 + 刷新登录时间
5. **签发token**:在事务外执行,失败不影响DB数据
```mermaid
flowchart TD
Start(["登录请求"]) --> Validate["验证authCode"]
Validate --> GetUserInfo["获取三方用户信息"]
GetUserInfo --> PreCheck{"本地有匹配用户?"}
PreCheck --> |是| SkipOrgCheck["跳过组织校验"]
PreCheck --> |否| OrgCheck["组织准入预校验"]
SkipOrgCheck --> DoLogin["事务内登录逻辑"]
OrgCheck --> DoLogin
DoLogin --> LocateUser["定位用户"]
LocateUser --> CheckEnabled{"用户是否启用?"}
CheckEnabled --> |否| ThrowError["抛出禁用错误"]
CheckEnabled --> |是| UpdateLoginTime["刷新登录时间"]
UpdateLoginTime --> CreateToken["签发token"]
CreateToken --> ReturnResult["返回登录结果"]
```
**更新** 重构后的认证流程更加健壮,事务处理避免了脏数据,组织准入预校验提升了性能,身份定位逻辑更加清晰。
图表来源
- [AuthServiceImpl.java:64-93](file://crm-auth/src/main/java/com/crm/auth/service/impl/AuthServiceImpl.java#L64-L93)
- [AuthServiceImpl.java:98-111](file://crm-auth/src/main/java/com/crm/auth/service/impl/AuthServiceImpl.java#L98-L111)
- [AuthServiceImpl.java:117-139](file://crm-auth/src/main/java/com/crm/auth/service/impl/AuthServiceImpl.java#L117-L139)
### 三层资源层级结构设计
系统现在支持完整的三层资源层级结构,通过MenuType枚举定义了目录、菜单、按钮三种资源类型:
- **目录(CATALOG)**:作为收纳容器,不承载页面,只能挂menu子节点
- **菜单(MENU)**:可导航的页面,只能挂button子节点
- **按钮(BUTTON)**:叶子节点,不可再挂子节点,承载权限码和接口映射
```mermaid
classDiagram
class MenuType {
+CATALOG : MenuType
+MENU : MenuType
+BUTTON : MenuType
+fromCode(code) : MenuType
+isLegalChild(parent, child) : boolean
1 month ago
}
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
1 month ago
}
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
1 month ago
}
MenuType <|-- SysMenu
SysMenu <..> ResourceNode : 双向转换
1 month ago
```
**更新** 三层资源层级结构在PermissionResolverImpl中得到了充分利用,visibleMenuTree方法会过滤掉button类型的菜单,只返回catalog和menu类型的菜单树。
图表来源
- [MenuType.java:12-52](file://crm-auth/src/main/java/com/crm/auth/domain/enums/MenuType.java#L12-L52)
- [SysMenu.java:12-76](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysMenu.java#L12-L76)
- [ResourceNode.java:16-84](file://crm-auth/src/main/java/com/crm/auth/domain/dto/ResourceNode.java#L16-L84)
### SysMenu实体增强设计
SysMenu实体经过大幅增强,现在支持按钮级别的细粒度权限控制:
- **基础字段**:parentId、menuName、menuType、path、component、icon、sort、visible
- **按钮级权限字段**:description(描述/备注)、perms(权限码)、denyBehavior(拒绝行为)、status(权限点状态)、apiUrl(接口URL)
- **树形结构支持**:children字段用于TreeUtils构建树时填充
**更新** SysMenu实体现在具备完整的按钮级权限控制能力,包括详细的权限描述、权限码、前端行为和API映射。
1 month ago
章节来源
- [SysMenu.java:12-76](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysMenu.java#L12-L76)
### ResourceNode DTO层次结构支持
ResourceNode DTO现在支持完整的层次结构,包含children字段:
- **层次结构字段**:`List<ResourceNode> children` - 子节点列表,仅在listAll()返回时填充
- **双向转换方法**:
- `fromEntity方法`:将SysMenu实体转换为ResourceNode DTO
- `toEntity方法`:将ResourceNode DTO转换回SysMenu实体
- **字段映射**:自动处理name↔menuName、route↔path、type↔menuType等字段映射
**更新** ResourceNode DTO现在支持层次结构,简化了前后端数据交互,提供了灵活的DTO转换机制和完整的树形数据支持。
章节来源
- [ResourceNode.java:16-84](file://crm-auth/src/main/java/com/crm/auth/domain/dto/ResourceNode.java#L16-L84)
### 统一资源树管理系统
完整的资源树管理系统,包含控制器、服务和接口,遵循全局接口契约:
#### ResourceController
提供标准化的RESTful API接口,采用显式动作后缀设计:
- `GET /api/resources/list`:**获取全量资源树(返回嵌套层次结构)**
- `POST /api/resources/saveOrUpdate`:新增或编辑节点
- `POST /api/resources/delete`:删除节点
- `POST /api/resources/icon/upload`:图标上传
#### ResourceServiceImpl
实现完整的业务逻辑:
- **层级约束验证**:确保父子关系的合法性,使用MenuType.isLegalChild()进行统一验证
- **字段必填校验**:根据不同类型验证必填字段
- **级联清理**:删除时自动清理角色授权引用
- **图标上传**:支持多种格式的图标文件上传
- **树形结构构建**:使用TreeUtils构建真正的层次结构
- **缓存失效**:保存和删除操作后调用apiPermissionCache.invalidate()
1 month ago
1 month ago
```mermaid
flowchart TD
Start(["保存资源节点"]) --> Validate["参数校验"]
Validate --> TypeCheck{"检查节点类型"}
TypeCheck --> |目录| CatalogRule["目录规则验证"]
TypeCheck --> |菜单| MenuRule["菜单规则验证"]
TypeCheck --> |按钮| ButtonRule["按钮规则验证"]
CatalogRule --> HierarchyCheck["层级约束检查"]
MenuRule --> HierarchyCheck
ButtonRule --> HierarchyCheck
HierarchyCheck --> ApplyMapping["DTO→Entity映射"]
ApplyMapping --> Save["保存至数据库"]
Save --> InvalidateCache["失效API权限缓存"]
InvalidateCache --> Return["返回ResourceNode"]
1 month ago
```
**更新** 资源树管理系统提供了完善的CRUD操作和严格的业务规则验证。validateHierarchy方法现在使用MenuType.isLegalChild()进行层级验证,避免了硬编码的魔术数字,提高了代码的可维护性和可读性。新增的缓存失效机制确保权限规则实时更新。
1 month ago
1 month ago
图表来源
- [ResourceController.java:1-56](file://crm-auth/src/main/java/com/crm/auth/controller/ResourceController.java#L1-56)
- [ResourceServiceImpl.java:55-97](file://crm-auth/src/main/java/com/crm/auth/service/impl/ResourceServiceImpl.java#L55-L97)
- [IResourceService.java:1-26](file://crm-auth/src/main/java/com/crm/auth/service/IResourceService.java#L1-L26)
1 month ago
### 数据权限范围控制(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 : "返回受限结果"
```
图表来源
- [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)
1 month ago
章节来源
- [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)
1 month ago
### 认证与安全配置(SecurityConfig、JwtAuthenticationFilter、TokenService)
- SecurityConfig:定义URL白名单、授权规则、跨域与异常处理器
- JwtAuthenticationFilter:解析JWT,填充认证上下文,集成新的PermissionResolver
1 month ago
- 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
+permissionResolver : PermissionResolver
1 month ago
}
class TokenService {
+createToken(user) String
+refreshToken(token) String
+logout(token) void
+validate(token) boolean
}
SecurityConfig --> JwtAuthenticationFilter : "注册过滤器"
JwtAuthenticationFilter --> TokenService : "验证/解析令牌"
JwtAuthenticationFilter --> PermissionResolver : "权限解析"
1 month ago
```
图表来源
- [SecurityConfig.java:1-200](file://crm-auth/src/main/java/com/crm/auth/config/SecurityConfig.java#L1-L200)
- [JwtAuthenticationFilter.java:1-66](file://crm-auth/src/main/java/com/crm/auth/security/JwtAuthenticationFilter.java#L1-L66)
- [TokenService.java:1-200](file://crm-auth/src/main/java/com/crm/auth/security/TokenService.java#L1-L200)
1 month ago
章节来源
- [SecurityConfig.java:1-200](file://crm-auth/src/main/java/com/crm/auth/config/SecurityConfig.java#L1-L200)
- [JwtAuthenticationFilter.java:1-66](file://crm-auth/src/main/java/com/crm/auth/security/JwtAuthenticationFilter.java#L1-L66)
- [TokenService.java:1-200](file://crm-auth/src/main/java/com/crm/auth/security/TokenService.java#L1-L200)
1 month ago
### 权限注解使用与最佳实践
- 接口级权限控制
- 在需要权限校验的方法上标注权限标识(如菜单code或按钮标识)
- 结合白名单跳过敏感接口校验
- 数据权限注解
- 在查询方法上标注 @DataScope,指定范围类型与目标表
- 确保 DataScopeTables 中已配置对应表的列映射
- 注意事项
- 避免在事务内频繁切换数据权限上下文
- 合理设置缓存失效时机,保证权限变更后即时生效
**更新** 基于新的PermissionResolver架构,权限控制更加模块化和安全化,fail-closed原则确保了权限解析失败的请求会被拒绝。新增的ApiPermissionInterceptor提供了URL级别的权限控制,与注解方式互补使用。
1 month ago
1 month ago
章节来源
- [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:16-35](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolver.java#L16-L35)
1 month ago
### 动态权限加载与缓存机制
- 动态加载
- 登录后根据用户角色拉取菜单树与按钮权限
- 将权限集合与菜单树写入缓存
- 缓存键设计
- 用户维度:user:{userId}:perms
- 角色维度:role:{roleId}:menuTree
- 缓存更新
- 角色/菜单变更触发失效
- 提供手动刷新接口供管理员使用
**更新** 新的PermissionResolverImpl实现了共享查询链优化,减少了重复查询,提高了性能表现。新增的ApiPermissionCache基于Caffeine提供进程内缓存,支持懒加载和主动失效。
1 month ago
1 month ago
章节来源
- [PermissionResolverImpl.java:118-139](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolverImpl.java#L118-L139)
- [ApiPermissionCache.java:37-63](file://crm-auth/src/main/java/com/crm/auth/security/ApiPermissionCache.java#L37-L63)
- [SysMenuServiceImpl.java:1-200](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysMenuServiceImpl.java#L1-L200)
- [SysRoleServiceImpl.java:1-200](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysRoleServiceImpl.java#L1-L200)
1 month ago
### 配置方法与初始化
- 权限配置
- PermissionConfig:集中管理权限相关开关与默认值
- 安全配置
- SecurityConfig:URL白名单、跨域、异常处理器
- 数据初始化
- DataInitializer:初始化默认角色、菜单、管理员账号等
**更新** DataInitializer现在支持三层资源层级结构的初始化,包括目录、菜单和按钮的完整权限体系。新增的WebMvcConfig负责注册API权限拦截器。
章节来源
- [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)
- [WebMvcConfig.java:19-23](file://crm-auth/src/main/java/com/crm/auth/config/WebMvcConfig.java#L19-L23)
### 资源树层级约束验证机制
资源树的层级约束验证机制通过MenuType枚举和validateHierarchy方法实现:
- **根节点验证**:根节点不允许添加button类型
- **父节点类型检查**:确保父节点存在且类型有效
- **层级关系验证**:使用MenuType.isLegalChild()方法进行统一的层级关系验证
- **空值安全处理**:防止未知菜单类型导致的NullPointerException
```mermaid
flowchart TD
Start(["验证层级关系"]) --> RootCheck{"是否根节点?"}
RootCheck --> |是| RootRule["根节点规则检查"]
RootCheck --> |否| ParentCheck["父节点存在性检查"]
RootCheck --> |否| ParentTypeCheck["父节点类型检查"]
ParentTypeCheck --> UnknownType{"父节点类型是否已知?"}
UnknownType --> |否| Error["抛出未知类型错误"]
UnknownType --> |是| LegalCheck["使用MenuType.isLegalChild验证"]
LegalCheck --> Valid{"层级关系合法?"}
Valid --> |是| Success["验证通过"]
Valid --> |否| ErrorMsg["抛出具体错误消息"]
RootRule --> Success
```
**更新** validateHierarchy方法现在完全依赖MenuType.isLegalChild()进行层级验证,消除了硬编码的魔术数字,提高了代码的可维护性和一致性。
图表来源
- [ResourceServiceImpl.java:174-202](file://crm-auth/src/main/java/com/crm/auth/service/impl/ResourceServiceImpl.java#L174-L202)
- [MenuType.java:37-51](file://crm-auth/src/main/java/com/crm/auth/domain/enums/MenuType.java#L37-L51)
章节来源
- [ResourceServiceImpl.java:174-202](file://crm-auth/src/main/java/com/crm/auth/service/impl/ResourceServiceImpl.java#L174-L202)
- [MenuType.java:37-51](file://crm-auth/src/main/java/com/crm/auth/domain/enums/MenuType.java#L37-L51)
### 路由路径处理逻辑改进
改进了路由路径处理逻辑,避免空字符串覆盖数据库值:
- **非空值覆盖原则**:只有当node.getRoute()为非空时才覆盖entity.getPath()
- **空串保留机制**:空字符串或空白字符不会覆盖数据库中已有的path值
- **编辑模式支持**:在编辑模式下,如果未提供route但数据库已有path则保持原值
这种改进确保了数据的一致性和完整性,避免了意外覆盖数据库中的有效数据。
章节来源
- [ResourceServiceImpl.java:243-246](file://crm-auth/src/main/java/com/crm/auth/service/impl/ResourceServiceImpl.java#L243-L246)
### 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严格遵循全局接口契约,所有写操作都使用POST + 动作后缀的模式,提升了API的一致性和可预测性。
章节来源
- [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工具类提供了高效的树形结构构建能力,PermissionResolverImpl中使用它来构建菜单树,ResourceServiceImpl中使用它来构建资源树。
图表来源
- [TreeUtils.java:36-71](file://crm-base/src/main/java/com/crm/base/utils/TreeUtils.java#L36-L71)
- [PermissionResolverImpl.java:115](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolverImpl.java#L115)
1 month ago
章节来源
- [TreeUtils.java:1-91](file://crm-base/src/main/java/com/crm/base/utils/TreeUtils.java#L1-L91)
- [PermissionResolverImpl.java:115](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolverImpl.java#L115)
1 month ago
## 依赖关系分析
- 模块依赖
- crm-auth 依赖 crm-base(异常、工具、数据可见性上下文)
- crm-app 依赖 crm-auth(作为应用入口)
- 组件耦合
- **PermissionResolverImpl** 依赖多个Mapper和DeptTreeCache
- **JwtAuthenticationFilter** 依赖PermissionResolver和TokenService
- **SystemController** 依赖PermissionResolver和其他服务
- **ApiPermissionInterceptor** 依赖ApiPermissionCache
- **ResourceServiceImpl** 依赖ApiPermissionCache进行缓存失效
1 month ago
- DataScopeInterceptor 依赖 DataScopeHelper 与 CrmSqlInjector
- SecurityConfig 依赖 JwtAuthenticationFilter 与异常处理器
```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
ResourceService --> ApiPermissionCache
JwtAuthenticationFilter --> PermissionResolver
PermissionResolver --> PermissionResolverImpl
SystemController --> PermissionResolver
ApiPermissionInterceptor --> ApiPermissionCache
1 month ago
```
**更新** 新的架构中,PermissionResolverImpl解耦了具体的权限解析逻辑,JwtAuthenticationFilter和SystemController都通过PermissionResolver接口进行依赖,降低了耦合度。新增的ApiPermissionInterceptor依赖ApiPermissionCache,ResourceServiceImpl通过ApiPermissionCache实现缓存失效。
1 month ago
图表来源
- [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)
1 month ago
章节来源
- [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)
1 month ago
## 性能考虑
- 缓存优先
- 菜单树与权限集合应缓存至Redis,降低重复查询
- 合理设置过期时间与失效策略
- 批量与懒加载
- 菜单树构建尽量使用批量查询与懒加载
- 数据权限SQL优化
- 在 DataScopeTables 中精确映射表与列,避免全表扫描
- 为常用过滤列添加索引
- **新增** 资源树操作优化
- **TreeUtils提供O(n)复杂度的树构建算法,性能显著提升**
- **listAll()方法直接返回树形结构,减少前端处理开销**
- 图标上传异步处理提升用户体验
- 使用MenuType枚举提高类型检查效率
- **新增** API权限拦截优化
- **ApiPermissionCache基于Caffeine提供高性能进程内缓存**
- **懒加载机制避免不必要的数据库查询**
- **AntPathMatcher提供高效的URL模式匹配**
**更新** 新的PermissionResolverImpl实现了共享查询链优化,通过authorizedMenus()方法复用查询结果,减少了重复的数据库访问。同时,PermissionGrant作为不可变值对象,避免了不必要的对象创建和修改开销。新增的ApiPermissionCache基于Caffeine提供高性能缓存,懒加载机制确保只在首次访问时加载规则。
1 month ago
## 故障排查指南
- 常见错误
- 未认证或令牌过期:检查 JwtAuthenticationFilter 与 TokenService 配置
- 权限不足:确认角色-菜单授权是否正确,缓存是否及时失效
- 数据权限不生效:检查 @DataScope 注解与 DataScopeTables 映射
- **新增** 权限解析失败:检查PermissionResolverImpl的实现和依赖注入
- **新增** API权限拦截403:检查ApiPermissionCache规则和用户权限
- **新增** 认证流程异常:检查AuthServiceImpl的事务处理和第三方登录逻辑
1 month ago
- 定位步骤
- 查看全局异常处理器输出
- 开启调试日志,观察拦截器与SQL注入过程
- 核对缓存键与失效时机
- **新增** 检查PermissionResolverImpl中的权限解析逻辑
- **新增** 验证PermissionGrant的值对象构造和数据完整性
- **新增** 确认JwtAuthenticationFilter中的fail-closed逻辑
- **新增** 检查SystemController中PermissionResolver的使用
- **新增** 验证ApiPermissionInterceptor的URL匹配逻辑
- **新增** 检查ResourceServiceImpl中的缓存失效调用
1 month ago
**更新** 对于新的三组件架构,建议特别关注PermissionResolverImpl的依赖注入是否正确,PermissionGrant的构造参数是否完整,以及JwtAuthenticationFilter中的fail-closed逻辑是否正常工作。新增的API权限拦截系统需要检查ApiPermissionCache的规则加载和用户权限匹配。
1 month ago
1 month ago
章节来源
- [GlobalExceptionHandlerAdvice.java:1-200](file://crm-base/src/main/java/com/crm/base/advice/GlobalExceptionHandlerAdvice.java#L1-L200)
- [JwtAuthenticationFilter.java:1-66](file://crm-auth/src/main/java/com/crm/auth/security/JwtAuthenticationFilter.java#L1-L66)
- [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)
- [PermissionResolverImpl.java:1-140](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolverImpl.java#L1-L140)
- [ApiPermissionInterceptor.java:38-80](file://crm-auth/src/main/java/com/crm/auth/security/ApiPermissionInterceptor.java#L38-L80)
- [AuthServiceImpl.java:64-93](file://crm-auth/src/main/java/com/crm/auth/service/impl/AuthServiceImpl.java#L64-L93)
1 month ago
## 结论
本权限管理系统以RBAC为核心,结合注解驱动的数据权限控制与拦截器实现的SQL改写,形成完整的权限校验与数据隔离方案。**通过本次重构,系统实现了PermissionResolver三组件架构,包括PermissionResolver接口、PermissionGrant不可变值对象和PermissionResolverImpl实现类,显著提升了权限解析的模块化设计和安全性。**
**最重要的改进是新的三组件架构采用了fail-closed安全原则,确保权限解析失败的请求会被拒绝;PermissionGrant作为不可变值对象保证了数据的一致性和线程安全;PermissionResolverImpl实现了共享查询链优化,减少了重复查询开销。** 通过JwtAuthenticationFilter和SystemController对PermissionResolver的统一使用,简化了权限解析的调用方式,提高了代码的可维护性和测试性。
**新增的动态API权限拦截系统通过ApiPermissionInterceptor和ApiPermissionCache提供了URL级别的权限控制,基于Caffeine缓存保证性能,fail-open策略确保向后兼容性。** 资源树变更时自动触发缓存失效,确保权限规则实时更新。
**改进的认证流程重构优化了事务处理,避免了脏数据问题,组织准入预校验提升了性能,身份定位逻辑更加清晰。** 新的架构还充分利用了三层资源层级结构(目录-菜单-按钮),在visibleMenuTree方法中正确过滤button类型的菜单,只返回catalog和menu类型的菜单树。TreeUtils工具类的O(n)算法相比之前的O(n²)算法有显著的性能提升。通过对PermissionResolverImpl中authorizedMenus方法的优化,实现了用户→角色→授权→资源的共享查询链,进一步提升了性能表现。
通过合理的缓存策略与配置化开关,可在保障安全性的同时提升性能与可维护性。建议在生产环境严格管理权限变更与缓存失效,确保权限一致性与实时性。
1 month ago
## 附录
- 术语
- RBAC:基于角色的访问控制
- 数据权限:基于用户所属组织或范围的查询限制
- fail-closed:失败关闭原则,权限解析失败即拒绝请求
- fail-open:失败开放原则,未匹配规则时放行请求
- 不可变值对象:一旦创建就不能修改的对象
- AntPathMatcher:Spring提供的URL模式匹配器
1 month ago
- 参考
- 实体与枚举:SysRole、SysMenu、DataScopeEnum、MenuType
- 数据传输对象:ResourceNode
- **新增** 权限解析三组件:PermissionResolver、PermissionGrant、PermissionResolverImpl
- **新增** 动态API权限拦截:ApiPermissionInterceptor、ApiPermissionCache、ApiPermissionRule
- 服务与拦截:DataScopeInterceptor、JwtAuthenticationFilter
- **新增** 系统集成:SystemController对PermissionResolver的使用
- 工具类:TreeUtils
- 配置与初始化:PermissionConfig、SecurityConfig、DataInitializer、WebMvcConfig
**更新** 重点关注新的PermissionResolver三组件架构,它们提供了更强大的权限解析能力和更好的模块化设计。PermissionGrant不可变值对象确保了数据安全,PermissionResolverImpl的共享查询链优化提升了性能。SystemController对PermissionResolver的直接使用简化了调用方式,提高了代码的可维护性。新增的ApiPermissionInterceptor和ApiPermissionCache提供了灵活的URL级别权限控制,AuthServiceImpl的重构优化了认证流程。