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.

386 lines
21 KiB

1 month ago
# 认证核心机制
<cite>
**本文引用的文件**
- [SecurityConfig.java](file://crm-auth/src/main/java/com/crm/auth/config/SecurityConfig.java)
- [JwtAuthenticationFilter.java](file://crm-auth/src/main/java/com/crm/auth/security/JwtAuthenticationFilter.java)
- [TokenService.java](file://crm-auth/src/main/java/com/crm/auth/security/TokenService.java)
- [AuthLoginUser.java](file://crm-auth/src/main/java/com/crm/auth/security/AuthLoginUser.java)
- [AuthController.java](file://crm-auth/src/main/java/com/crm/auth/controller/AuthController.java)
- [AuthService.java](file://crm-auth/src/main/java/com/crm/auth/service/IAuthService.java)
- [AuthServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/AuthServiceImpl.java)
- [DataScopeInterceptor.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeInterceptor.java)
- [SecurityExceptionHandlers.java](file://crm-auth/src/main/java/com/crm/auth/security/SecurityExceptionHandlers.java)
- [AuthConstants.java](file://crm-auth/src/main/java/com/crm/auth/constant/AuthConstants.java)
- [application.yml](file://crm-auth/src/main/resources/application.yml)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考虑](#性能考虑)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录:配置示例与最佳实践](#附录配置示例与最佳实践)
## 简介
本技术文档聚焦于认证核心机制,围绕JWT令牌的生成、验证与刷新、安全过滤器链(请求拦截、用户身份解析、权限校验)、以及会话管理与并发控制等高级特性进行系统化说明。文档同时给出完整的配置要点与故障排查建议,帮助读者快速理解并落地实现。
## 项目结构
认证相关代码主要位于 crm-auth 模块中,关键目录与职责如下:
- config:安全配置类,定义过滤器链、跨域、授权策略等
- security:安全核心组件,包括JWT过滤器、令牌服务、登录用户上下文、数据范围拦截器、异常处理器
- controller:认证入口控制器,提供登录、登出、刷新等接口
- service:认证业务逻辑,封装用户校验、角色权限加载、第三方登录等
- constant:常量定义,如令牌前缀、过期时间、错误码等
- resources:应用配置文件,包含JWT、Redis、安全策略等参数
```mermaid
graph TB
subgraph "crm-auth"
C["config/SecurityConfig"] --> F["security/JwtAuthenticationFilter"]
F --> T["security/TokenService"]
F --> U["security/AuthLoginUser"]
F --> DSI["security/DataScopeInterceptor"]
F --> SEH["security/SecurityExceptionHandlers"]
Ctrl["controller/AuthController"] --> Svc["service/IAuthService + impl/AuthServiceImpl"]
Svc --> DB["持久层(用户/角色/菜单)"]
T --> Redis["缓存(Redis)"]
end
```
**图表来源**
- [SecurityConfig.java](file://crm-auth/src/main/java/com/crm/auth/config/SecurityConfig.java)
- [JwtAuthenticationFilter.java](file://crm-auth/src/main/java/com/crm/auth/security/JwtAuthenticationFilter.java)
- [TokenService.java](file://crm-auth/src/main/java/com/crm/auth/security/TokenService.java)
- [AuthLoginUser.java](file://crm-auth/src/main/java/com/crm/auth/security/AuthLoginUser.java)
- [DataScopeInterceptor.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeInterceptor.java)
- [SecurityExceptionHandlers.java](file://crm-auth/src/main/java/com/crm/auth/security/SecurityExceptionHandlers.java)
- [AuthController.java](file://crm-auth/src/main/java/com/crm/auth/controller/AuthController.java)
- [IAuthService.java](file://crm-auth/src/main/java/com/crm/auth/service/IAuthService.java)
- [AuthServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/AuthServiceImpl.java)
**章节来源**
- [SecurityConfig.java](file://crm-auth/src/main/java/com/crm/auth/config/SecurityConfig.java)
- [JwtAuthenticationFilter.java](file://crm-auth/src/main/java/com/crm/auth/security/JwtAuthenticationFilter.java)
- [TokenService.java](file://crm-auth/src/main/java/com/crm/auth/security/TokenService.java)
- [AuthLoginUser.java](file://crm-auth/src/main/java/com/crm/auth/security/AuthLoginUser.java)
- [AuthController.java](file://crm-auth/src/main/java/com/crm/auth/controller/AuthController.java)
- [IAuthService.java](file://crm-auth/src/main/java/com/crm/auth/service/IAuthService.java)
- [AuthServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/AuthServiceImpl.java)
- [DataScopeInterceptor.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeInterceptor.java)
- [SecurityExceptionHandlers.java](file://crm-auth/src/main/java/com/crm/auth/security/SecurityExceptionHandlers.java)
- [application.yml](file://crm-auth/src/main/resources/application.yml)
## 核心组件
- 安全配置(SecurityConfig):注册过滤器链、白名单路径、跨域、授权规则等
- JWT过滤器(JwtAuthenticationFilter):从请求头提取令牌、校验签名、构建认证上下文
- 令牌服务(TokenService):负责JWT签发、解析、刷新、黑名单/在线会话管理
- 登录用户(AuthLoginUser):承载当前用户身份、角色、权限、数据范围等上下文信息
- 数据范围拦截器(DataScopeInterceptor):基于注解或上下文注入SQL数据范围条件
- 异常处理器(SecurityExceptionHandlers):统一处理认证失败、权限不足、令牌异常等
- 认证控制器(AuthController):暴露登录、登出、刷新、获取用户信息等接口
- 认证服务(IAuthService/AuthServiceImpl):封装用户校验、角色权限加载、第三方登录流程
**章节来源**
- [SecurityConfig.java](file://crm-auth/src/main/java/com/crm/auth/config/SecurityConfig.java)
- [JwtAuthenticationFilter.java](file://crm-auth/src/main/java/com/crm/auth/security/JwtAuthenticationFilter.java)
- [TokenService.java](file://crm-auth/src/main/java/com/crm/auth/security/TokenService.java)
- [AuthLoginUser.java](file://crm-auth/src/main/java/com/crm/auth/security/AuthLoginUser.java)
- [DataScopeInterceptor.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeInterceptor.java)
- [SecurityExceptionHandlers.java](file://crm-auth/src/main/java/com/crm/auth/security/SecurityExceptionHandlers.java)
- [AuthController.java](file://crm-auth/src/main/java/com/crm/auth/controller/AuthController.java)
- [IAuthService.java](file://crm-auth/src/main/java/com/crm/auth/service/IAuthService.java)
- [AuthServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/AuthServiceImpl.java)
## 架构总览
下图展示了认证核心机制的整体架构与交互关系,涵盖请求进入、JWT校验、用户上下文构建、权限校验与数据范围过滤的关键路径。
```mermaid
sequenceDiagram
participant Client as "客户端"
participant Filter as "JwtAuthenticationFilter"
participant TokenSvc as "TokenService"
participant AuthSrv as "IAuthService"
participant SecCtx as "安全上下文(AuthLoginUser)"
participant DSInt as "DataScopeInterceptor"
participant Controller as "AuthController/业务控制器"
Client->>Filter : "携带Authorization : Bearer <token>"
Filter->>TokenSvc : "解析并校验JWT签名/过期"
TokenSvc-->>Filter : "返回有效载荷(用户ID/角色/权限)"
Filter->>SecCtx : "构建认证上下文(含数据范围)"
Filter->>DSInt : "执行数据范围拦截"
DSInt-->>Filter : "注入SQL数据范围条件"
Filter->>Controller : "放行到目标方法"
Controller-->>Client : "返回业务结果"
```
**图表来源**
- [JwtAuthenticationFilter.java](file://crm-auth/src/main/java/com/crm/auth/security/JwtAuthenticationFilter.java)
- [TokenService.java](file://crm-auth/src/main/java/com/crm/auth/security/TokenService.java)
- [AuthLoginUser.java](file://crm-auth/src/main/java/com/crm/auth/security/AuthLoginUser.java)
- [DataScopeInterceptor.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeInterceptor.java)
- [AuthController.java](file://crm-auth/src/main/java/com/crm/auth/controller/AuthController.java)
## 详细组件分析
### JWT令牌生命周期与刷新机制
- 签发:登录成功后由TokenService生成访问令牌与可选的刷新令牌,写入响应头或响应体;必要时将令牌元数据(如设备指纹、IP、过期时间)存入Redis用于在线会话管理
- 校验:JwtAuthenticationFilter在每次请求时提取Authorization头,调用TokenService校验签名、有效期、是否被拉黑;通过后构建AuthLoginUser上下文
- 刷新:当访问令牌即将过期或已过期时,使用刷新令牌换取新的访问令牌;刷新过程中可校验刷新令牌有效性、设备一致性、并发限制等
- 注销:服务端维护令牌黑名单或撤销在线会话,确保立即失效
```mermaid
flowchart TD
Start(["开始"]) --> Extract["从请求头提取令牌"]
Extract --> Validate{"令牌有效?"}
Validate --> |否| HandleInvalid["抛出认证异常/返回未授权"]
Validate --> |是| BuildCtx["构建AuthLoginUser上下文"]
BuildCtx --> Scope["数据范围拦截器注入SQL条件"]
Scope --> Pass["放行至控制器"]
Pass --> End(["结束"])
HandleInvalid --> End
```
**图表来源**
- [JwtAuthenticationFilter.java](file://crm-auth/src/main/java/com/crm/auth/security/JwtAuthenticationFilter.java)
- [TokenService.java](file://crm-auth/src/main/java/com/crm/auth/security/TokenService.java)
- [AuthLoginUser.java](file://crm-auth/src/main/java/com/crm/auth/security/AuthLoginUser.java)
- [DataScopeInterceptor.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeInterceptor.java)
**章节来源**
- [TokenService.java](file://crm-auth/src/main/java/com/crm/auth/security/TokenService.java)
- [JwtAuthenticationFilter.java](file://crm-auth/src/main/java/com/crm/auth/security/JwtAuthenticationFilter.java)
- [AuthController.java](file://crm-auth/src/main/java/com/crm/auth/controller/AuthController.java)
- [AuthConstants.java](file://crm-auth/src/main/java/com/crm/auth/constant/AuthConstants.java)
### 安全过滤器链与请求拦截
- 过滤器链顺序:CORS -> TraceId -> JwtAuthenticationFilter -> DataScopeInterceptor -> 业务控制器
- 白名单:静态资源、健康检查、部分公开接口可跳过JWT校验
- 鉴权:在过滤器或控制器层面根据角色/权限决定放行与否
- 异常:统一由SecurityExceptionHandlers捕获并返回标准错误格式
```mermaid
sequenceDiagram
participant Client as "客户端"
participant Filter as "JwtAuthenticationFilter"
participant DSInt as "DataScopeInterceptor"
participant Handler as "SecurityExceptionHandlers"
participant Ctrl as "业务控制器"
Client->>Filter : "HTTP请求"
Filter->>Filter : "白名单判断/跨域处理"
Filter->>Filter : "JWT解析与校验"
Filter->>DSInt : "数据范围拦截"
DSInt-->>Filter : "注入数据范围"
Filter->>Ctrl : "放行"
Ctrl-->>Client : "成功响应"
Note over Filter,Handler : "若发生认证/权限异常,交由异常处理器统一处理"
```
**图表来源**
- [SecurityConfig.java](file://crm-auth/src/main/java/com/crm/auth/config/SecurityConfig.java)
- [JwtAuthenticationFilter.java](file://crm-auth/src/main/java/com/crm/auth/security/JwtAuthenticationFilter.java)
- [DataScopeInterceptor.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeInterceptor.java)
- [SecurityExceptionHandlers.java](file://crm-auth/src/main/java/com/crm/auth/security/SecurityExceptionHandlers.java)
**章节来源**
- [SecurityConfig.java](file://crm-auth/src/main/java/com/crm/auth/config/SecurityConfig.java)
- [JwtAuthenticationFilter.java](file://crm-auth/src/main/java/com/crm/auth/security/JwtAuthenticationFilter.java)
- [DataScopeInterceptor.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeInterceptor.java)
- [SecurityExceptionHandlers.java](file://crm-auth/src/main/java/com/crm/auth/security/SecurityExceptionHandlers.java)
### AuthLoginUser设计模式与会话管理
- 设计模式:采用“登录用户上下文”模式,将用户标识、角色、权限、数据范围等信息聚合为单一对象,便于在过滤器、拦截器、服务层与控制器间传递
- 会话管理:结合Redis存储在线会话元数据(如设备指纹、IP、最后活跃时间),支持单点登录、强制下线、并发登录控制
- 数据可见性:通过数据范围上下文(部门、角色、自定义范围)动态注入SQL条件,实现行级数据隔离
```mermaid
classDiagram
class AuthLoginUser {
+用户ID
+用户名
+角色列表
+权限集合
+数据范围
+设备指纹
+最后活跃时间
+构造(用户信息, 角色, 权限, 数据范围)
+校验(令牌元数据)
}
class TokenService {
+签发JWT()
+解析JWT()
+刷新令牌()
+加入黑名单()
+查询在线会话()
}
class JwtAuthenticationFilter {
+doFilter(request, response)
-解析令牌()
-构建上下文()
}
class DataScopeInterceptor {
+preHandle(request, response, handler)
-注入数据范围()
}
JwtAuthenticationFilter --> TokenService : "校验/解析"
JwtAuthenticationFilter --> AuthLoginUser : "构建上下文"
DataScopeInterceptor --> AuthLoginUser : "读取数据范围"
```
**图表来源**
- [AuthLoginUser.java](file://crm-auth/src/main/java/com/crm/auth/security/AuthLoginUser.java)
- [TokenService.java](file://crm-auth/src/main/java/com/crm/auth/security/TokenService.java)
- [JwtAuthenticationFilter.java](file://crm-auth/src/main/java/com/crm/auth/security/JwtAuthenticationFilter.java)
- [DataScopeInterceptor.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeInterceptor.java)
**章节来源**
- [AuthLoginUser.java](file://crm-auth/src/main/java/com/crm/auth/security/AuthLoginUser.java)
- [TokenService.java](file://crm-auth/src/main/java/com/crm/auth/security/TokenService.java)
- [JwtAuthenticationFilter.java](file://crm-auth/src/main/java/com/crm/auth/security/JwtAuthenticationFilter.java)
- [DataScopeInterceptor.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeInterceptor.java)
### 认证业务流程(登录、刷新、登出)
- 登录:AuthController接收登录参数,调用IAuthService/AuthServiceImpl进行用户校验、角色权限加载,成功后由TokenService签发JWT并返回
- 刷新:客户端携带刷新令牌请求刷新接口,服务端校验后签发新访问令牌
- 登出:服务端将令牌加入黑名单或移除在线会话,使旧令牌立即失效
```mermaid
sequenceDiagram
participant Client as "客户端"
participant Ctrl as "AuthController"
participant Svc as "IAuthService/AuthServiceImpl"
participant Token as "TokenService"
Client->>Ctrl : "POST /auth/login"
Ctrl->>Svc : "校验用户/加载角色权限"
Svc-->>Ctrl : "返回用户信息"
Ctrl->>Token : "签发JWT(访问/刷新)"
Token-->>Ctrl : "返回令牌"
Ctrl-->>Client : "登录成功响应"
Client->>Ctrl : "POST /auth/refresh"
Ctrl->>Token : "校验刷新令牌并签发新访问令牌"
Token-->>Ctrl : "返回新令牌"
Ctrl-->>Client : "刷新成功响应"
Client->>Ctrl : "POST /auth/logout"
Ctrl->>Token : "加入黑名单/移除在线会话"
Token-->>Ctrl : "操作结果"
Ctrl-->>Client : "登出成功响应"
```
**图表来源**
- [AuthController.java](file://crm-auth/src/main/java/com/crm/auth/controller/AuthController.java)
- [IAuthService.java](file://crm-auth/src/main/java/com/crm/auth/service/IAuthService.java)
- [AuthServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/AuthServiceImpl.java)
- [TokenService.java](file://crm-auth/src/main/java/com/crm/auth/security/TokenService.java)
**章节来源**
- [AuthController.java](file://crm-auth/src/main/java/com/crm/auth/controller/AuthController.java)
- [IAuthService.java](file://crm-auth/src/main/java/com/crm/auth/service/IAuthService.java)
- [AuthServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/AuthServiceImpl.java)
- [TokenService.java](file://crm-auth/src/main/java/com/crm/auth/security/TokenService.java)
## 依赖关系分析
- 组件内聚与耦合:
- JwtAuthenticationFilter依赖TokenService与AuthLoginUser,低耦合高内聚
- DataScopeInterceptor依赖AuthLoginUser的数据范围字段,避免侵入业务逻辑
- SecurityConfig集中管理过滤器链与白名单,降低分散配置风险
- 外部依赖:
- Redis用于在线会话与令牌黑名单管理
- MyBatis/数据库用于用户、角色、菜单等基础数据
- 潜在循环依赖:
- 通过接口解耦(IAuthService与其实现类),避免直接循环引用
```mermaid
graph LR
SC["SecurityConfig"] --> JF["JwtAuthenticationFilter"]
JF --> TS["TokenService"]
JF --> ALU["AuthLoginUser"]
JF --> DSI["DataScopeInterceptor"]
DSI --> ALU
AC["AuthController"] --> IA["IAuthService"]
IA --> AIS["AuthServiceImpl"]
TS --> Redis["Redis"]
```
**图表来源**
- [SecurityConfig.java](file://crm-auth/src/main/java/com/crm/auth/config/SecurityConfig.java)
- [JwtAuthenticationFilter.java](file://crm-auth/src/main/java/com/crm/auth/security/JwtAuthenticationFilter.java)
- [TokenService.java](file://crm-auth/src/main/java/com/crm/auth/security/TokenService.java)
- [AuthLoginUser.java](file://crm-auth/src/main/java/com/crm/auth/security/AuthLoginUser.java)
- [DataScopeInterceptor.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeInterceptor.java)
- [AuthController.java](file://crm-auth/src/main/java/com/crm/auth/controller/AuthController.java)
- [IAuthService.java](file://crm-auth/src/main/java/com/crm/auth/service/IAuthService.java)
- [AuthServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/AuthServiceImpl.java)
**章节来源**
- [SecurityConfig.java](file://crm-auth/src/main/java/com/crm/auth/config/SecurityConfig.java)
- [JwtAuthenticationFilter.java](file://crm-auth/src/main/java/com/crm/auth/security/JwtAuthenticationFilter.java)
- [TokenService.java](file://crm-auth/src/main/java/com/crm/auth/security/TokenService.java)
- [AuthLoginUser.java](file://crm-auth/src/main/java/com/crm/auth/security/AuthLoginUser.java)
- [DataScopeInterceptor.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeInterceptor.java)
- [AuthController.java](file://crm-auth/src/main/java/com/crm/auth/controller/AuthController.java)
- [IAuthService.java](file://crm-auth/src/main/java/com/crm/auth/service/IAuthService.java)
- [AuthServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/AuthServiceImpl.java)
## 性能考虑
- JWT无状态校验:减少数据库查询,提升吞吐;但需配合Redis做黑名单与在线会话管理
- 令牌刷新策略:合理设置访问令牌短时效、刷新令牌长时效,降低频繁鉴权开销
- 数据范围优化:在拦截器阶段注入SQL条件,避免在业务层重复计算
- 缓存热点:用户角色与权限可缓存至Redis,缩短鉴权路径
- 并发控制:基于设备指纹与IP限制同一用户并发会话数,防止资源滥用
[本节为通用性能建议,不直接分析具体文件]
## 故障排查指南
- 常见错误类型:
- 令牌缺失或格式错误:检查Authorization头与Bearer前缀
- 签名无效或已过期:核对密钥配置与系统时钟同步
- 权限不足:确认用户角色与接口权限映射
- 数据范围异常:检查数据范围上下文是否正确注入
- 定位步骤:
- 查看JwtAuthenticationFilter日志,确认令牌解析与校验过程
- 检查TokenService的黑名单与在线会话状态
- 确认SecurityConfig白名单与跨域配置
- 核查DataScopeInterceptor的数据范围注入逻辑
- 恢复措施:
- 清理黑名单或重置在线会话
- 重新签发令牌并更新客户端缓存
- 修正权限映射或数据范围配置
**章节来源**
- [JwtAuthenticationFilter.java](file://crm-auth/src/main/java/com/crm/auth/security/JwtAuthenticationFilter.java)
- [TokenService.java](file://crm-auth/src/main/java/com/crm/auth/security/TokenService.java)
- [SecurityConfig.java](file://crm-auth/src/main/java/com/crm/auth/config/SecurityConfig.java)
- [DataScopeInterceptor.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeInterceptor.java)
- [SecurityExceptionHandlers.java](file://crm-auth/src/main/java/com/crm/auth/security/SecurityExceptionHandlers.java)
## 结论
本认证核心机制以JWT为核心,结合过滤器链与数据范围拦截,实现了高效、可扩展且安全的认证与授权体系。通过TokenService与会话管理,支持令牌刷新、黑名单、并发控制等高级特性;AuthLoginUser作为统一上下文,简化了跨层身份传递。合理的配置与监控能有效保障系统的稳定性与安全性。
[本节为总结性内容,不直接分析具体文件]
## 附录:配置示例与最佳实践
- JWT配置要点:
- 密钥长度与算法选择(建议使用强随机密钥与RS256/HS512)
- 访问令牌与刷新令牌过期时间(短效访问+长效刷新)
- 令牌前缀与头部名称(如Authorization: Bearer)
- 安全策略:
- 白名单最小化,仅开放必要接口
- 跨域严格限定来源与方法
- 统一异常处理与错误码规范
- 会话与并发:
- 基于Redis存储在线会话,支持设备指纹与IP绑定
- 限制同一用户并发会话数,防止账号共享
- 监控与审计:
- 记录登录、刷新、登出事件
- 统计令牌校验失败率与超时情况
- 定期清理过期会话与黑名单
**章节来源**
- [application.yml](file://crm-auth/src/main/resources/application.yml)
- [AuthConstants.java](file://crm-auth/src/main/java/com/crm/auth/constant/AuthConstants.java)
- [SecurityConfig.java](file://crm-auth/src/main/java/com/crm/auth/config/SecurityConfig.java)