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.
389 lines
20 KiB
389 lines
20 KiB
|
1 month ago
|
# 动态API权限拦截器
|
||
|
|
|
||
|
|
<cite>
|
||
|
|
**本文引用的文件**
|
||
|
|
- [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)
|
||
|
|
- [ResourceServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/ResourceServiceImpl.java)
|
||
|
|
- [SysMenu.java](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysMenu.java)
|
||
|
|
- [MenuType.java](file://crm-auth/src/main/java/com/crm/auth/domain/enums/MenuType.java)
|
||
|
|
- [PermissionResolver.java](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolver.java)
|
||
|
|
- [PermissionResolverImpl.java](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolverImpl.java)
|
||
|
|
- [PermissionGrant.java](file://crm-auth/src/main/java/com/crm/auth/security/PermissionGrant.java)
|
||
|
|
- [DataVisibilityContext.java](file://crm-base/src/main/java/com/crm/base/security/DataVisibilityContext.java)
|
||
|
|
- [DataVisibility.java](file://crm-base/src/main/java/com/crm/base/security/DataVisibility.java)
|
||
|
|
- [DataScopeLevel.java](file://crm-base/src/main/java/com/crm/base/security/DataScopeLevel.java)
|
||
|
|
- [PermissionConfig.java](file://crm-auth/src/main/java/com/crm/auth/config/PermissionConfig.java)
|
||
|
|
- [ApiPermissionInterceptorTest.java](file://crm-auth/src/test/java/com/crm/auth/security/ApiPermissionInterceptorTest.java)
|
||
|
|
</cite>
|
||
|
|
|
||
|
|
## 目录
|
||
|
|
1. [简介](#简介)
|
||
|
|
2. [项目结构](#项目结构)
|
||
|
|
3. [核心组件](#核心组件)
|
||
|
|
4. [架构总览](#架构总览)
|
||
|
|
5. [详细组件分析](#详细组件分析)
|
||
|
|
6. [依赖关系分析](#依赖关系分析)
|
||
|
|
7. [性能考量](#性能考量)
|
||
|
|
8. [故障排查指南](#故障排查指南)
|
||
|
|
9. [结论](#结论)
|
||
|
|
10. [附录](#附录)
|
||
|
|
|
||
|
|
## 简介
|
||
|
|
本文件围绕“动态API权限拦截器”的实现与使用进行系统化说明。该能力通过MVC拦截器在请求进入Controller之前,依据用户已授权的权限码集合与缓存的API规则(来自菜单资源树中的按钮节点)进行匹配校验,实现细粒度的接口级访问控制。其关键特性包括:
|
||
|
|
- 基于Ant风格路径模式匹配(支持*与**)
|
||
|
|
- fail-open策略:未注册规则的URL默认放行
|
||
|
|
- 进程内Caffeine缓存规则列表,资源变更时主动失效
|
||
|
|
- 与Spring Security上下文集成,从当前认证主体提取权限码集合
|
||
|
|
- 与数据权限体系解耦,仅负责“是否允许调用某接口”的判定
|
||
|
|
|
||
|
|
## 项目结构
|
||
|
|
围绕动态API权限拦截器的相关代码分布在以下模块与包中:
|
||
|
|
- crm-auth/security:拦截器、规则、缓存、权限解析等核心安全组件
|
||
|
|
- crm-auth/config:MVC拦截器注册配置
|
||
|
|
- crm-auth/service/impl:资源树服务,负责保存/删除后触发权限规则缓存失效
|
||
|
|
- crm-auth/domain/entity & enums:菜单实体与类型枚举,承载apiUrl与perms等字段
|
||
|
|
- crm-base/security:数据可见性上下文与范围模型(与API权限解耦但同属安全域)
|
||
|
|
|
||
|
|
```mermaid
|
||
|
|
graph TB
|
||
|
|
subgraph "crm-auth"
|
||
|
|
A["ApiPermissionInterceptor<br/>拦截器"]
|
||
|
|
B["ApiPermissionCache<br/>规则缓存"]
|
||
|
|
C["ApiPermissionRule<br/>规则记录"]
|
||
|
|
D["WebMvcConfig<br/>拦截器注册"]
|
||
|
|
E["ResourceServiceImpl<br/>资源服务(失效缓存)"]
|
||
|
|
F["SysMenu<br/>菜单实体(apiUrl/perms)"]
|
||
|
|
G["MenuType<br/>菜单类型枚举"]
|
||
|
|
H["PermissionResolver / Impl<br/>权限解析引擎"]
|
||
|
|
I["PermissionGrant<br/>授权结果"]
|
||
|
|
end
|
||
|
|
subgraph "crm-base"
|
||
|
|
J["DataVisibilityContext<br/>数据可见性上下文"]
|
||
|
|
K["DataVisibility<br/>数据可见性模型"]
|
||
|
|
L["DataScopeLevel<br/>数据范围档位"]
|
||
|
|
end
|
||
|
|
D --> A
|
||
|
|
A --> B
|
||
|
|
B --> F
|
||
|
|
B --> G
|
||
|
|
E --> B
|
||
|
|
H --> I
|
||
|
|
I --> J
|
||
|
|
J --> K
|
||
|
|
K --> L
|
||
|
|
```
|
||
|
|
|
||
|
|
**图表来源**
|
||
|
|
- [ApiPermissionInterceptor.java:1-82](file://crm-auth/src/main/java/com/crm/auth/security/ApiPermissionInterceptor.java#L1-L82)
|
||
|
|
- [ApiPermissionCache.java:1-65](file://crm-auth/src/main/java/com/crm/auth/security/ApiPermissionCache.java#L1-L65)
|
||
|
|
- [ApiPermissionRule.java:1-11](file://crm-auth/src/main/java/com/crm/auth/security/ApiPermissionRule.java#L1-L11)
|
||
|
|
- [WebMvcConfig.java:1-25](file://crm-auth/src/main/java/com/crm/auth/config/WebMvcConfig.java#L1-L25)
|
||
|
|
- [ResourceServiceImpl.java:1-200](file://crm-auth/src/main/java/com/crm/auth/service/impl/ResourceServiceImpl.java#L1-L200)
|
||
|
|
- [SysMenu.java:1-77](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysMenu.java#L1-L77)
|
||
|
|
- [MenuType.java:1-52](file://crm-auth/src/main/java/com/crm/auth/domain/enums/MenuType.java#L1-L52)
|
||
|
|
- [PermissionResolver.java:1-36](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolver.java#L1-L36)
|
||
|
|
- [PermissionResolverImpl.java:1-140](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolverImpl.java#L1-L140)
|
||
|
|
- [PermissionGrant.java:1-68](file://crm-auth/src/main/java/com/crm/auth/security/PermissionGrant.java#L1-L68)
|
||
|
|
- [DataVisibilityContext.java:1-45](file://crm-base/src/main/java/com/crm/base/security/DataVisibilityContext.java#L1-L45)
|
||
|
|
- [DataVisibility.java:1-75](file://crm-base/src/main/java/com/crm/base/security/DataVisibility.java#L1-L75)
|
||
|
|
- [DataScopeLevel.java:1-51](file://crm-base/src/main/java/com/crm/base/security/DataScopeLevel.java#L1-L51)
|
||
|
|
|
||
|
|
**章节来源**
|
||
|
|
- [WebMvcConfig.java:1-25](file://crm-auth/src/main/java/com/crm/auth/config/WebMvcConfig.java#L1-L25)
|
||
|
|
- [ApiPermissionInterceptor.java:1-82](file://crm-auth/src/main/java/com/crm/auth/security/ApiPermissionInterceptor.java#L1-L82)
|
||
|
|
- [ApiPermissionCache.java:1-65](file://crm-auth/src/main/java/com/crm/auth/security/ApiPermissionCache.java#L1-L65)
|
||
|
|
|
||
|
|
## 核心组件
|
||
|
|
- ApiPermissionInterceptor:MVC拦截器,负责请求前拦截、规则匹配、权限判定与响应处理
|
||
|
|
- ApiPermissionCache:进程内规则缓存,懒加载并支持主动失效
|
||
|
|
- ApiPermissionRule:规则记录(pattern→perms)
|
||
|
|
- WebMvcConfig:注册拦截器到/api/**路径
|
||
|
|
- ResourceServiceImpl:资源树CRUD后触发缓存失效
|
||
|
|
- SysMenu/MenuType:菜单实体与类型,承载apiUrl与perms等元数据
|
||
|
|
- PermissionResolver/Impl/Grant:权限解析引擎与结果对象(为前端菜单与角色/权限码聚合提供支撑)
|
||
|
|
- DataVisibilityContext/Visibility/Level:数据可见性与范围档位(与API权限解耦)
|
||
|
|
|
||
|
|
**章节来源**
|
||
|
|
- [ApiPermissionInterceptor.java:1-82](file://crm-auth/src/main/java/com/crm/auth/security/ApiPermissionInterceptor.java#L1-L82)
|
||
|
|
- [ApiPermissionCache.java:1-65](file://crm-auth/src/main/java/com/crm/auth/security/ApiPermissionCache.java#L1-L65)
|
||
|
|
- [ApiPermissionRule.java:1-11](file://crm-auth/src/main/java/com/crm/auth/security/ApiPermissionRule.java#L1-L11)
|
||
|
|
- [WebMvcConfig.java:1-25](file://crm-auth/src/main/java/com/crm/auth/config/WebMvcConfig.java#L1-L25)
|
||
|
|
- [ResourceServiceImpl.java:1-200](file://crm-auth/src/main/java/com/crm/auth/service/impl/ResourceServiceImpl.java#L1-L200)
|
||
|
|
- [SysMenu.java:1-77](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysMenu.java#L1-L77)
|
||
|
|
- [MenuType.java:1-52](file://crm-auth/src/main/java/com/crm/auth/domain/enums/MenuType.java#L1-L52)
|
||
|
|
- [PermissionResolver.java:1-36](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolver.java#L1-L36)
|
||
|
|
- [PermissionResolverImpl.java:1-140](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolverImpl.java#L1-L140)
|
||
|
|
- [PermissionGrant.java:1-68](file://crm-auth/src/main/java/com/crm/auth/security/PermissionGrant.java#L1-L68)
|
||
|
|
- [DataVisibilityContext.java:1-45](file://crm-base/src/main/java/com/crm/base/security/DataVisibilityContext.java#L1-L45)
|
||
|
|
- [DataVisibility.java:1-75](file://crm-base/src/main/java/com/crm/base/security/DataVisibility.java#L1-L75)
|
||
|
|
- [DataScopeLevel.java:1-51](file://crm-base/src/main/java/com/crm/base/security/DataScopeLevel.java#L1-L51)
|
||
|
|
|
||
|
|
## 架构总览
|
||
|
|
下图展示了请求进入后的整体流程:JWT过滤器完成认证后,MVC拦截器根据缓存的规则进行权限判定;资源树变更后由服务层触发缓存失效。
|
||
|
|
|
||
|
|
```mermaid
|
||
|
|
sequenceDiagram
|
||
|
|
participant Client as "客户端"
|
||
|
|
participant JWT as "JWT过滤器"
|
||
|
|
participant MVC as "WebMvcConfig"
|
||
|
|
participant Interceptor as "ApiPermissionInterceptor"
|
||
|
|
participant Cache as "ApiPermissionCache"
|
||
|
|
participant DB as "数据库(sys_menu)"
|
||
|
|
participant Controller as "业务Controller"
|
||
|
|
Client->>JWT : "HTTP 请求"
|
||
|
|
JWT-->>Client : "设置SecurityContext(含权限码)"
|
||
|
|
Client->>MVC : "路由分发"
|
||
|
|
MVC->>Interceptor : "preHandle(/api/**)"
|
||
|
|
Interceptor->>Cache : "getRules()"
|
||
|
|
alt "缓存命中"
|
||
|
|
Cache-->>Interceptor : "规则列表"
|
||
|
|
else "缓存未命中"
|
||
|
|
Cache->>DB : "查询启用且带apiUrl的按钮节点"
|
||
|
|
DB-->>Cache : "菜单节点集合"
|
||
|
|
Cache-->>Interceptor : "构建规则列表并缓存"
|
||
|
|
end
|
||
|
|
Interceptor->>Interceptor : "Ant路径匹配 + 权限码比对"
|
||
|
|
alt "有权限或无规则"
|
||
|
|
Interceptor-->>Controller : "放行"
|
||
|
|
Controller-->>Client : "业务响应"
|
||
|
|
else "无权限"
|
||
|
|
Interceptor-->>Client : "403 拒绝"
|
||
|
|
end
|
||
|
|
```
|
||
|
|
|
||
|
|
**图表来源**
|
||
|
|
- [WebMvcConfig.java:1-25](file://crm-auth/src/main/java/com/crm/auth/config/WebMvcConfig.java#L1-L25)
|
||
|
|
- [ApiPermissionInterceptor.java:1-82](file://crm-auth/src/main/java/com/crm/auth/security/ApiPermissionInterceptor.java#L1-L82)
|
||
|
|
- [ApiPermissionCache.java:1-65](file://crm-auth/src/main/java/com/crm/auth/security/ApiPermissionCache.java#L1-L65)
|
||
|
|
- [SysMenu.java:1-77](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysMenu.java#L1-L77)
|
||
|
|
|
||
|
|
## 详细组件分析
|
||
|
|
|
||
|
|
### 拦截器:ApiPermissionInterceptor
|
||
|
|
- 职责:在请求进入Controller前,从SecurityContext获取用户权限码集合,结合缓存规则进行匹配校验
|
||
|
|
- 匹配策略:AntPathMatcher支持*与**通配;若未匹配任何规则则放行(fail-open)
|
||
|
|
- 失败处理:匹配到规则但无对应权限时返回403,并写入统一JSON提示
|
||
|
|
|
||
|
|
```mermaid
|
||
|
|
flowchart TD
|
||
|
|
Start(["进入 preHandle"]) --> GetUri["获取请求URI"]
|
||
|
|
GetUri --> GetRules["从缓存获取规则列表"]
|
||
|
|
GetRules --> Match{"是否存在匹配规则?"}
|
||
|
|
Match --> |否| Allow["放行(fail-open)"]
|
||
|
|
Match --> |是| GetAuth["从SecurityContext取用户权限码集合"]
|
||
|
|
GetAuth --> CheckPerm{"任一规则 perms 是否在用户权限中?"}
|
||
|
|
CheckPerm --> |是| Allow
|
||
|
|
CheckPerm --> |否| Deny["返回403并写回JSON"]
|
||
|
|
Allow --> End(["结束"])
|
||
|
|
Deny --> End
|
||
|
|
```
|
||
|
|
|
||
|
|
**图表来源**
|
||
|
|
- [ApiPermissionInterceptor.java:1-82](file://crm-auth/src/main/java/com/crm/auth/security/ApiPermissionInterceptor.java#L1-L82)
|
||
|
|
|
||
|
|
**章节来源**
|
||
|
|
- [ApiPermissionInterceptor.java:1-82](file://crm-auth/src/main/java/com/crm/auth/security/ApiPermissionInterceptor.java#L1-L82)
|
||
|
|
|
||
|
|
### 规则缓存:ApiPermissionCache
|
||
|
|
- 职责:以单key形式缓存全部规则列表,首次访问懒加载,后续直接命中
|
||
|
|
- 数据来源:查询sys_menu中类型为button、状态enabled且包含apiUrl的记录,映射为规则
|
||
|
|
- 失效机制:资源树变更时调用invalidate清空缓存,下次请求重建
|
||
|
|
|
||
|
|
```mermaid
|
||
|
|
classDiagram
|
||
|
|
class ApiPermissionCache {
|
||
|
|
-SysMenuMapper sysMenuMapper
|
||
|
|
-Cache~String,List~ cache
|
||
|
|
+getRules() ApiPermissionRule[]
|
||
|
|
+invalidate() void
|
||
|
|
-loadRules() ApiPermissionRule[]
|
||
|
|
}
|
||
|
|
class ApiPermissionRule {
|
||
|
|
+String pattern
|
||
|
|
+String perms
|
||
|
|
}
|
||
|
|
class SysMenu {
|
||
|
|
+Integer menuType
|
||
|
|
+String status
|
||
|
|
+String apiUrl
|
||
|
|
+String perms
|
||
|
|
}
|
||
|
|
ApiPermissionCache --> ApiPermissionRule : "构建"
|
||
|
|
ApiPermissionCache --> SysMenu : "读取"
|
||
|
|
```
|
||
|
|
|
||
|
|
**图表来源**
|
||
|
|
- [ApiPermissionCache.java:1-65](file://crm-auth/src/main/java/com/crm/auth/security/ApiPermissionCache.java#L1-L65)
|
||
|
|
- [ApiPermissionRule.java:1-11](file://crm-auth/src/main/java/com/crm/auth/security/ApiPermissionRule.java#L1-L11)
|
||
|
|
- [SysMenu.java:1-77](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysMenu.java#L1-L77)
|
||
|
|
|
||
|
|
**章节来源**
|
||
|
|
- [ApiPermissionCache.java:1-65](file://crm-auth/src/main/java/com/crm/auth/security/ApiPermissionCache.java#L1-L65)
|
||
|
|
- [SysMenu.java:1-77](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysMenu.java#L1-L77)
|
||
|
|
- [MenuType.java:1-52](file://crm-auth/src/main/java/com/crm/auth/domain/enums/MenuType.java#L1-L52)
|
||
|
|
|
||
|
|
### 资源服务与缓存失效:ResourceServiceImpl
|
||
|
|
- 职责:对资源树进行增删改操作,并在保存/删除后主动失效权限规则缓存
|
||
|
|
- 关键点:save与delete均调用apiPermissionCache.invalidate(),确保下一次请求重建规则
|
||
|
|
|
||
|
|
```mermaid
|
||
|
|
sequenceDiagram
|
||
|
|
participant Admin as "管理员"
|
||
|
|
participant Service as "ResourceServiceImpl"
|
||
|
|
participant MenuSvc as "ISysMenuService"
|
||
|
|
participant Cache as "ApiPermissionCache"
|
||
|
|
participant DB as "数据库"
|
||
|
|
Admin->>Service : "保存/删除资源节点"
|
||
|
|
Service->>MenuSvc : "持久化菜单实体"
|
||
|
|
MenuSvc-->>Service : "成功"
|
||
|
|
Service->>Cache : "invalidate()"
|
||
|
|
Cache-->>Service : "缓存已失效"
|
||
|
|
Service-->>Admin : "返回结果"
|
||
|
|
```
|
||
|
|
|
||
|
|
**图表来源**
|
||
|
|
- [ResourceServiceImpl.java:1-200](file://crm-auth/src/main/java/com/crm/auth/service/impl/ResourceServiceImpl.java#L1-L200)
|
||
|
|
- [ApiPermissionCache.java:1-65](file://crm-auth/src/main/java/com/crm/auth/security/ApiPermissionCache.java#L1-L65)
|
||
|
|
|
||
|
|
**章节来源**
|
||
|
|
- [ResourceServiceImpl.java:1-200](file://crm-auth/src/main/java/com/crm/auth/service/impl/ResourceServiceImpl.java#L1-L200)
|
||
|
|
|
||
|
|
### 权限解析引擎:PermissionResolver/Impl/Grant
|
||
|
|
- 职责:一次resolve计算用户的“数据可见性+权限码并集+角色编码”,供登录前后端渲染与鉴权使用
|
||
|
|
- 输出:PermissionGrant封装了DataVisibility、permCodes与roleCodes,并提供asAuthorities生成Spring Security authorities
|
||
|
|
|
||
|
|
```mermaid
|
||
|
|
classDiagram
|
||
|
|
class PermissionResolver {
|
||
|
|
<<interface>>
|
||
|
|
+resolve(userId) PermissionGrant
|
||
|
|
+visibleMenuTree(userId) SysMenu[]
|
||
|
|
}
|
||
|
|
class PermissionResolverImpl {
|
||
|
|
-SysUserRoleMapper
|
||
|
|
-SysRoleMapper
|
||
|
|
-SysRoleMenuMapper
|
||
|
|
-SysMenuMapper
|
||
|
|
-AuthUserMapper
|
||
|
|
-DeptTreeCache
|
||
|
|
-SysUserDeptMapper
|
||
|
|
+resolve(userId) PermissionGrant
|
||
|
|
+visibleMenuTree(userId) SysMenu[]
|
||
|
|
}
|
||
|
|
class PermissionGrant {
|
||
|
|
-DataVisibility visibility
|
||
|
|
-Set~String~ permCodes
|
||
|
|
-Set~String~ roleCodes
|
||
|
|
+asAuthorities() SimpleGrantedAuthority[]
|
||
|
|
}
|
||
|
|
class DataVisibility {
|
||
|
|
+visibilityScope() VisibilityScope
|
||
|
|
+dataOwnership() DataOwnership
|
||
|
|
}
|
||
|
|
class DataScopeLevel {
|
||
|
|
<<enum>>
|
||
|
|
+SELF
|
||
|
|
+DEPT
|
||
|
|
+DEPT_AND_CHILDREN
|
||
|
|
+ALL
|
||
|
|
}
|
||
|
|
PermissionResolver <|.. PermissionResolverImpl
|
||
|
|
PermissionResolverImpl --> PermissionGrant : "返回"
|
||
|
|
PermissionGrant --> DataVisibility : "包含"
|
||
|
|
DataVisibility --> DataScopeLevel : "引用"
|
||
|
|
```
|
||
|
|
|
||
|
|
**图表来源**
|
||
|
|
- [PermissionResolver.java:1-36](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolver.java#L1-L36)
|
||
|
|
- [PermissionResolverImpl.java:1-140](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolverImpl.java#L1-L140)
|
||
|
|
- [PermissionGrant.java:1-68](file://crm-auth/src/main/java/com/crm/auth/security/PermissionGrant.java#L1-L68)
|
||
|
|
- [DataVisibility.java:1-75](file://crm-base/src/main/java/com/crm/base/security/DataVisibility.java#L1-L75)
|
||
|
|
- [DataScopeLevel.java:1-51](file://crm-base/src/main/java/com/crm/base/security/DataScopeLevel.java#L1-L51)
|
||
|
|
|
||
|
|
**章节来源**
|
||
|
|
- [PermissionResolver.java:1-36](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolver.java#L1-L36)
|
||
|
|
- [PermissionResolverImpl.java:1-140](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolverImpl.java#L1-L140)
|
||
|
|
- [PermissionGrant.java:1-68](file://crm-auth/src/main/java/com/crm/auth/security/PermissionGrant.java#L1-L68)
|
||
|
|
- [DataVisibility.java:1-75](file://crm-base/src/main/java/com/crm/base/security/DataVisibility.java#L1-L75)
|
||
|
|
- [DataScopeLevel.java:1-51](file://crm-base/src/main/java/com/crm/base/security/DataScopeLevel.java#L1-L51)
|
||
|
|
|
||
|
|
### 数据可见性上下文:DataVisibilityContext
|
||
|
|
- 职责:以ThreadLocal存储当前请求的数据可见性范围,供数据权限拦截器与公共字段填充器读取
|
||
|
|
- 生命周期:请求开始时装载,结束时清理;异步场景需显式重新装载
|
||
|
|
|
||
|
|
**章节来源**
|
||
|
|
- [DataVisibilityContext.java:1-45](file://crm-base/src/main/java/com/crm/base/security/DataVisibilityContext.java#L1-L45)
|
||
|
|
|
||
|
|
## 依赖关系分析
|
||
|
|
- 拦截器依赖缓存,缓存依赖菜单实体与类型枚举
|
||
|
|
- 资源服务依赖菜单服务与缓存,用于触发失效
|
||
|
|
- 权限解析引擎依赖多个Mapper与部门树缓存,产出授权结果
|
||
|
|
- MVC配置将拦截器注册到/api/**路径
|
||
|
|
|
||
|
|
```mermaid
|
||
|
|
graph LR
|
||
|
|
WebMvcConfig --> ApiPermissionInterceptor
|
||
|
|
ApiPermissionInterceptor --> ApiPermissionCache
|
||
|
|
ApiPermissionCache --> SysMenu
|
||
|
|
ApiPermissionCache --> MenuType
|
||
|
|
ResourceServiceImpl --> ApiPermissionCache
|
||
|
|
PermissionResolverImpl --> SysMenu
|
||
|
|
PermissionResolverImpl --> SysRoleMenu
|
||
|
|
PermissionResolverImpl --> AuthUser
|
||
|
|
PermissionResolverImpl --> DeptTreeCache
|
||
|
|
PermissionGrant --> DataVisibility
|
||
|
|
DataVisibility --> DataScopeLevel
|
||
|
|
```
|
||
|
|
|
||
|
|
**图表来源**
|
||
|
|
- [WebMvcConfig.java:1-25](file://crm-auth/src/main/java/com/crm/auth/config/WebMvcConfig.java#L1-L25)
|
||
|
|
- [ApiPermissionInterceptor.java:1-82](file://crm-auth/src/main/java/com/crm/auth/security/ApiPermissionInterceptor.java#L1-L82)
|
||
|
|
- [ApiPermissionCache.java:1-65](file://crm-auth/src/main/java/com/crm/auth/security/ApiPermissionCache.java#L1-L65)
|
||
|
|
- [SysMenu.java:1-77](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysMenu.java#L1-L77)
|
||
|
|
- [MenuType.java:1-52](file://crm-auth/src/main/java/com/crm/auth/domain/enums/MenuType.java#L1-L52)
|
||
|
|
- [ResourceServiceImpl.java:1-200](file://crm-auth/src/main/java/com/crm/auth/service/impl/ResourceServiceImpl.java#L1-L200)
|
||
|
|
- [PermissionResolverImpl.java:1-140](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolverImpl.java#L1-L140)
|
||
|
|
- [PermissionGrant.java:1-68](file://crm-auth/src/main/java/com/crm/auth/security/PermissionGrant.java#L1-L68)
|
||
|
|
- [DataVisibility.java:1-75](file://crm-base/src/main/java/com/crm/base/security/DataVisibility.java#L1-L75)
|
||
|
|
- [DataScopeLevel.java:1-51](file://crm-base/src/main/java/com/crm/base/security/DataScopeLevel.java#L1-L51)
|
||
|
|
|
||
|
|
**章节来源**
|
||
|
|
- [PermissionConfig.java:1-55](file://crm-auth/src/main/java/com/crm/auth/config/PermissionConfig.java#L1-L55)
|
||
|
|
|
||
|
|
## 性能考量
|
||
|
|
- 规则缓存:采用Caffeine单key缓存,避免每次请求都查库;首次加载与失效后重建为唯一开销
|
||
|
|
- Ant匹配:内存中字符串匹配,复杂度与规则数量线性相关;建议合理拆分规则与避免过度通配
|
||
|
|
- 权限解析:一次resolve聚合多表查询,适合登录后一次性计算并复用;注意大数据量下的N+1问题(已通过批量查询优化)
|
||
|
|
- 线程上下文:DataVisibilityContext基于ThreadLocal,避免跨线程传递导致的额外开销
|
||
|
|
|
||
|
|
[本节为通用指导,不直接分析具体文件]
|
||
|
|
|
||
|
|
## 故障排查指南
|
||
|
|
- 现象:接口被403拒绝
|
||
|
|
- 检查用户是否拥有对应perms(可从SecurityContext或PermissionGrant中查看)
|
||
|
|
- 确认API URL是否与规则pattern匹配(Ant通配是否正确)
|
||
|
|
- 确认菜单节点状态是否为enabled且存在apiUrl
|
||
|
|
- 现象:修改资源后权限未生效
|
||
|
|
- 确认ResourceServiceImpl.save/delete是否调用了apiPermissionCache.invalidate()
|
||
|
|
- 检查缓存是否被其他逻辑覆盖或异常未失效
|
||
|
|
- 现象:未注册URL被拒绝
|
||
|
|
- 按fail-open设计,未匹配规则应放行;如被拒绝,检查是否有全局拦截器或网关层限制
|
||
|
|
|
||
|
|
**章节来源**
|
||
|
|
- [ApiPermissionInterceptor.java:1-82](file://crm-auth/src/main/java/com/crm/auth/security/ApiPermissionInterceptor.java#L1-L82)
|
||
|
|
- [ApiPermissionCache.java:1-65](file://crm-auth/src/main/java/com/crm/auth/security/ApiPermissionCache.java#L1-L65)
|
||
|
|
- [ResourceServiceImpl.java:1-200](file://crm-auth/src/main/java/com/crm/auth/service/impl/ResourceServiceImpl.java#L1-L200)
|
||
|
|
|
||
|
|
## 结论
|
||
|
|
动态API权限拦截器通过“规则缓存+拦截器匹配”的方式,实现了灵活、可配置的接口级权限控制。其与数据权限体系解耦,既保证了安全性,又具备良好的扩展性与性能表现。配合资源树管理与缓存失效机制,能够在运行时动态调整权限策略,满足复杂业务场景需求。
|
||
|
|
|
||
|
|
[本节为总结性内容,不直接分析具体文件]
|
||
|
|
|
||
|
|
## 附录
|
||
|
|
- 单元测试用例覆盖了典型场景:未注册URL放行、匹配且有权限放行、匹配但无权限拒绝、Ant通配匹配、停用节点不生成规则、多规则任一权限放行等
|
||
|
|
|
||
|
|
**章节来源**
|
||
|
|
- [ApiPermissionInterceptorTest.java:1-162](file://crm-auth/src/test/java/com/crm/auth/security/ApiPermissionInterceptorTest.java#L1-L162)
|