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.
25 KiB
25 KiB
JWT认证机制
**本文引用的文件** - [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) - [AuthProperties.java](file://crm-auth/src/main/java/com/crm/auth/config/AuthProperties.java) - [AuthController.java](file://crm-auth/src/main/java/com/crm/auth/controller/AuthController.java) - [LoginParam.java](file://crm-auth/src/main/java/com/crm/auth/domain/param/LoginParam.java) - [LoginResultDTO.java](file://crm-auth/src/main/java/com/crm/auth/domain/dto/LoginResultDTO.java) - [UserInfoDTO.java](file://crm-auth/src/main/java/com/crm/auth/domain/dto/UserInfoDTO.java) - [AuthUser.java](file://crm-auth/src/main/java/com/crm/auth/domain/entity/AuthUser.java) - [AuthIdentity.java](file://crm-auth/src/main/java/com/crm/auth/domain/entity/AuthIdentity.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) - [AuthUserMapper.java](file://crm-auth/src/main/java/com/crm/auth/mapper/AuthUserMapper.java) - [AuthIdentityMapper.java](file://crm-auth/src/main/java/com/crm/auth/mapper/AuthIdentityMapper.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) - [CorsConfig.java](file://crm-base/src/main/java/com/crm/base/config/CorsConfig.java) - [RedisConfig.java](file://crm-base/src/main/java/com/crm/base/config/RedisConfig.java) - [SecurityUtils.java](file://crm-base/src/main/java/com/crm/base/security/SecurityUtils.java) - [LoginUser.java](file://crm-base/src/main/java/com/crm/base/security/LoginUser.java)目录
简介
本文件围绕JWT认证机制,系统性解析令牌结构、签发流程、验证与刷新策略,重点说明JwtAuthenticationFilter的拦截与注入逻辑,以及TokenService的令牌管理能力。同时给出安全配置最佳实践(密钥管理、过期策略、跨域支持等),并提供常见问题排查方法与性能优化建议,帮助读者快速落地并稳定运行JWT鉴权体系。
项目结构
本项目采用多模块设计,认证相关代码集中在crm-auth模块,基础能力在crm-base模块提供。JWT认证的关键位置如下:
- 安全配置与属性:SecurityConfig、AuthProperties
- 过滤器与令牌服务:JwtAuthenticationFilter、TokenService
- 登录接口与数据模型:AuthController、LoginParam、LoginResultDTO、UserInfoDTO
- 用户与身份实体:AuthUser、AuthIdentity
- 服务与持久化:IAuthService、AuthServiceImpl、AuthUserMapper、AuthIdentityMapper
- 常量与配置:AuthConstants、application.yml
- 跨域与缓存:CorsConfig、RedisConfig
- 工具类:SecurityUtils、LoginUser
graph TB
subgraph "认证模块 crm-auth"
AC["AuthController"]
AP["AuthProperties"]
SC["SecurityConfig"]
JF["JwtAuthenticationFilter"]
TS["TokenService"]
IA["IAuthService"]
AS["AuthServiceImpl"]
AU["AuthUser"]
AI["AuthIdentity"]
AMU["AuthUserMapper"]
AMI["AuthIdentityMapper"]
Cst["AuthConstants"]
Yml["application.yml"]
end
subgraph "基础模块 crm-base"
CC["CorsConfig"]
RC["RedisConfig"]
SU["SecurityUtils"]
LU["LoginUser"]
end
AC --> TS
AC --> IA
IA --> AS
AS --> AMU
AS --> AMI
JF --> TS
SC --> JF
SC --> CC
TS --> RC
TS --> Cst
TS --> Yml
SU --> LU
图表来源
- SecurityConfig.java
- JwtAuthenticationFilter.java
- TokenService.java
- AuthController.java
- AuthProperties.java
- AuthServiceImpl.java
- AuthUserMapper.java
- AuthIdentityMapper.java
- AuthConstants.java
- application.yml
- CorsConfig.java
- RedisConfig.java
- SecurityUtils.java
- LoginUser.java
章节来源
- SecurityConfig.java
- JwtAuthenticationFilter.java
- TokenService.java
- AuthController.java
- AuthProperties.java
- AuthServiceImpl.java
- AuthUserMapper.java
- AuthIdentityMapper.java
- AuthConstants.java
- application.yml
- CorsConfig.java
- RedisConfig.java
- SecurityUtils.java
- LoginUser.java
核心组件
- JwtAuthenticationFilter:请求级拦截器,负责从请求头提取JWT、校验签名与有效期、构建认证上下文并注入到安全上下文。
- TokenService:令牌工厂与生命周期管理者,负责生成、解析、续期、撤销、黑名单管理等。
- SecurityConfig:Spring Security配置,注册过滤器、设置放行路径、跨域与异常处理。
- AuthController:对外暴露登录、注销、刷新等接口,调用服务层完成认证与令牌发放。
- IAuthService/AuthServiceImpl:业务认证实现,校验用户名密码或第三方身份,组装用户信息。
- 数据模型:LoginParam、LoginResultDTO、UserInfoDTO、AuthUser、AuthIdentity。
- 配置与常量:AuthProperties、AuthConstants、application.yml、CorsConfig、RedisConfig。
- 工具类:SecurityUtils、LoginUser用于获取当前登录用户与安全上下文操作。
章节来源
- JwtAuthenticationFilter.java
- TokenService.java
- SecurityConfig.java
- AuthController.java
- IAuthService.java
- AuthServiceImpl.java
- LoginParam.java
- LoginResultDTO.java
- UserInfoDTO.java
- AuthUser.java
- AuthIdentity.java
- AuthProperties.java
- AuthConstants.java
- application.yml
- CorsConfig.java
- RedisConfig.java
- SecurityUtils.java
- LoginUser.java
架构总览
JWT认证的整体流程包括:客户端发起登录,服务端校验凭证后签发JWT;后续请求携带JWT,过滤器解析并注入用户信息;业务方法通过工具类获取当前用户。令牌续期与撤销由TokenService统一管理,必要时结合Redis进行黑名单或会话控制。
sequenceDiagram
participant Client as "客户端"
participant Controller as "AuthController"
participant Service as "IAuthService/AuthServiceImpl"
participant Token as "TokenService"
participant Filter as "JwtAuthenticationFilter"
participant SecCfg as "SecurityConfig"
participant Redis as "Redis(可选)"
Note over Client,SecCfg : 登录阶段
Client->>Controller : POST /auth/login
Controller->>Service : 校验用户名/密码或第三方身份
Service-->>Controller : 用户信息与权限
Controller->>Token : 签发JWT(含用户ID、角色、权限等)
Token-->>Controller : 返回access_token/refresh_token
Controller-->>Client : 登录成功响应
Note over Client,Filter : 受保护资源访问
Client->>Filter : 携带Authorization : Bearer <token>
Filter->>Token : 解析并验证签名/过期/黑名单
Token-->>Filter : 解析后的用户信息
Filter->>SecCfg : 写入SecurityContext
Filter-->>Client : 放行至业务控制器
Note over Client,Token : 刷新令牌
Client->>Controller : POST /auth/refresh
Controller->>Token : 使用refresh_token换取新access_token
Token-->>Controller : 新令牌
Controller-->>Client : 刷新成功响应
图表来源
- AuthController.java
- IAuthService.java
- AuthServiceImpl.java
- TokenService.java
- JwtAuthenticationFilter.java
- SecurityConfig.java
- RedisConfig.java
详细组件分析
JwtAuthenticationFilter工作原理
- 请求拦截:在Spring Security过滤链中优先执行,读取Authorization头中的Bearer令牌。
- 令牌解析:委托TokenService解析并校验签名、过期时间、黑名单状态。
- 用户信息注入:将解析出的用户信息封装为认证对象,写入SecurityContext,供后续授权判断与业务使用。
- 异常处理:对非法令牌、缺失令牌、解析失败等情况统一抛出异常或拒绝访问。
flowchart TD
Start(["进入过滤器"]) --> ReadHeader["读取Authorization头"]
ReadHeader --> HasToken{"是否存在Bearer令牌?"}
HasToken --> |否| PassThrough["跳过认证<br/>交由后续过滤器或放行规则"]
HasToken --> |是| Parse["调用TokenService解析令牌"]
Parse --> Valid{"是否有效且未过期?"}
Valid --> |否| Reject["拒绝访问(401/403)"]
Valid --> |是| BuildCtx["构建认证上下文并注入SecurityContext"]
BuildCtx --> Continue["继续过滤器链/放行至控制器"]
PassThrough --> End(["结束"])
Reject --> End
Continue --> End
图表来源
- JwtAuthenticationFilter.java
- TokenService.java
- SecurityConfig.java
章节来源
- JwtAuthenticationFilter.java
- TokenService.java
- SecurityConfig.java
TokenService令牌管理
- 生成:根据用户信息生成JWT,包含必要声明(如用户ID、角色、权限、扩展信息等),设置过期时间。
- 验证:校验签名、过期时间、黑名单状态;可结合Redis做在线会话或强制下线。
- 续期:基于refresh_token签发新的access_token,支持滑动过期策略。
- 撤销:将令牌加入黑名单或使refresh_token失效,支持批量撤销与按用户维度撤销。
- 存储:可选择无状态(仅JWT)或有状态(Redis记录会话/黑名单)。
classDiagram
class TokenService {
+generateAccessToken(user) string
+generateRefreshToken(user) string
+parseAndValidate(token) UserInfo
+refreshAccessToken(refreshToken) string
+revoke(token) void
+isBlacklisted(token) bool
+extendExpiry(token) bool
}
class RedisConfig {
+redisTemplate
}
class AuthConstants {
+ACCESS_TOKEN_PREFIX
+REFRESH_TOKEN_PREFIX
+EXPIRE_ACCESS_SECONDS
+EXPIRE_REFRESH_SECONDS
}
TokenService --> RedisConfig : "可选 : 黑名单/会话"
TokenService --> AuthConstants : "读取令牌前缀与过期配置"
图表来源
- TokenService.java
- RedisConfig.java
- AuthConstants.java
章节来源
- TokenService.java
- AuthConstants.java
- RedisConfig.java
登录与令牌签发流程
- 客户端提交登录参数(用户名/密码或第三方标识)。
- 服务层校验凭证,查询用户与身份信息,组装用户上下文。
- TokenService签发access_token与refresh_token,返回给客户端。
- 客户端保存令牌并在后续请求中携带。
sequenceDiagram
participant Client as "客户端"
participant AC as "AuthController"
participant SA as "AuthServiceImpl"
participant TS as "TokenService"
Client->>AC : POST /auth/login(LoginParam)
AC->>SA : authenticate(LoginParam)
SA-->>AC : UserInfoDTO(用户信息+权限)
AC->>TS : generateAccessToken(UserInfoDTO)
TS-->>AC : access_token
AC->>TS : generateRefreshToken(UserInfoDTO)
TS-->>AC : refresh_token
AC-->>Client : LoginResultDTO{access_token, refresh_token}
图表来源
- AuthController.java
- AuthServiceImpl.java
- TokenService.java
- LoginParam.java
- LoginResultDTO.java
- UserInfoDTO.java
章节来源
- AuthController.java
- AuthServiceImpl.java
- TokenService.java
- LoginParam.java
- LoginResultDTO.java
- UserInfoDTO.java
用户信息注入与上下文使用
- JwtAuthenticationFilter解析成功后,将用户信息封装为认证对象并写入SecurityContext。
- 业务层通过SecurityUtils获取当前登录用户(LoginUser),避免重复解析JWT。
- 权限与数据范围控制可在过滤器链之后进行,结合注解或拦截器实现。
sequenceDiagram
participant Filter as "JwtAuthenticationFilter"
participant TS as "TokenService"
participant SecCtx as "SecurityContext"
participant Utils as "SecurityUtils"
participant Biz as "业务控制器"
Filter->>TS : parseAndValidate(token)
TS-->>Filter : 用户信息
Filter->>SecCtx : 写入认证对象
Biz->>Utils : getCurrentUser()
Utils-->>Biz : LoginUser
Biz-->>Biz : 执行业务逻辑
图表来源
- JwtAuthenticationFilter.java
- TokenService.java
- SecurityUtils.java
- LoginUser.java
章节来源
- JwtAuthenticationFilter.java
- TokenService.java
- SecurityUtils.java
- LoginUser.java
刷新与撤销策略
- 刷新:客户端使用refresh_token调用刷新接口,服务端校验通过后签发新的access_token,支持滑动过期。
- 撤销:服务端可将access_token或refresh_token加入黑名单,或在Redis中删除会话键,强制下线。
- 策略建议:短时效access_token配合长时效refresh_token,减少泄露风险;定期清理黑名单与过期会话。
flowchart TD
Start(["刷新入口"]) --> CheckRefresh["校验refresh_token有效性"]
CheckRefresh --> Valid{"是否有效?"}
Valid --> |否| Error["返回401/403"]
Valid --> |是| RevokeOld["撤销旧access_token(可选)"]
RevokeOld --> GenNew["签发新access_token"]
GenNew --> Return["返回新令牌"]
Error --> End(["结束"])
Return --> End
图表来源
- TokenService.java
- AuthController.java
章节来源
- TokenService.java
- AuthController.java
数据模型与实体关系
- AuthUser:用户主表,包含账号、密码、状态等。
- AuthIdentity:第三方身份关联,支持多种登录方式。
- DTO与Param:登录参数、登录结果、用户信息传输对象。
erDiagram
AUTH_USER {
bigint id PK
string username UK
string password
int status
datetime created_at
datetime updated_at
}
AUTH_IDENTITY {
bigint id PK
bigint user_id FK
string identity_type
string identity_value
datetime created_at
}
AUTH_USER ||--o{ AUTH_IDENTITY : "拥有"
图表来源
- AuthUser.java
- AuthIdentity.java
章节来源
- AuthUser.java
- AuthIdentity.java
依赖关系分析
- 过滤器依赖TokenService进行令牌解析与校验。
- TokenService依赖RedisConfig(可选)与AuthConstants(令牌前缀与过期配置)。
- 认证控制器依赖服务层完成凭证校验与用户信息组装。
- 安全配置注册过滤器、设置放行路径与跨域策略。
graph LR
JF["JwtAuthenticationFilter"] --> TS["TokenService"]
TS --> RC["RedisConfig"]
TS --> ACst["AuthConstants"]
AC["AuthController"] --> TS
AC --> IA["IAuthService"]
IA --> AS["AuthServiceImpl"]
AS --> AMU["AuthUserMapper"]
AS --> AMI["AuthIdentityMapper"]
SC["SecurityConfig"] --> JF
SC --> CC["CorsConfig"]
图表来源
- JwtAuthenticationFilter.java
- TokenService.java
- RedisConfig.java
- AuthConstants.java
- AuthController.java
- IAuthService.java
- AuthServiceImpl.java
- AuthUserMapper.java
- AuthIdentityMapper.java
- SecurityConfig.java
- CorsConfig.java
章节来源
- JwtAuthenticationFilter.java
- TokenService.java
- AuthController.java
- IAuthService.java
- AuthServiceImpl.java
- AuthUserMapper.java
- AuthIdentityMapper.java
- SecurityConfig.java
- CorsConfig.java
性能考量
- 令牌解析开销:尽量精简JWT载荷,避免过大payload导致序列化/反序列化开销。
- Redis交互:黑名单与刷新令牌校验需尽量减少网络往返,合理设置超时与连接池。
- 过滤器链顺序:确保JwtAuthenticationFilter尽早执行,减少无效请求进入业务层。
- 缓存策略:用户信息、权限列表可缓存以减少数据库压力。
- 并发与限流:登录与刷新接口应加限流与防重放措施。
[本节为通用指导,不直接分析具体文件]
故障排查指南
- 401未认证:检查Authorization头格式是否正确、令牌是否过期、是否被拉黑。
- 403禁止访问:确认用户权限与资源访问规则是否匹配。
- 解析失败:核对签名密钥、算法配置、时区与时间同步问题。
- 刷新失败:检查refresh_token是否有效、是否已被撤销或过期。
- 跨域错误:确认CORS配置允许的来源、方法与头部。
章节来源
- JwtAuthenticationFilter.java
- TokenService.java
- SecurityConfig.java
- CorsConfig.java
结论
本方案以JwtAuthenticationFilter与TokenService为核心,实现了无状态与有状态相结合的JWT认证机制。通过合理的令牌结构与生命周期管理、严格的安全配置与跨域支持,能够满足企业级应用的高可用与高安全需求。建议在生产环境强化密钥管理、启用HTTPS、实施限流与审计,持续监控令牌使用与健康指标。
[本节为总结性内容,不直接分析具体文件]
附录
- 安全配置最佳实践
- 密钥管理:使用强随机密钥,定期轮换,生产环境通过环境变量或密钥管理服务注入。
- 过期策略:access_token短时效(如15分钟),refresh_token较长时效(如7天),支持滑动过期。
- 跨域支持:明确允许的源、方法与头部,避免使用通配符。
- 黑名单与会话:结合Redis实现强制下线、设备管理与会话统计。
- 日志与审计:记录登录、刷新、撤销事件,便于追踪与合规。
[本节为通用指导,不直接分析具体文件]