14 KiB
14 KiB
安全认证
**本文引用的文件** - [AuthProperties.java](file://fms-api/src/main/java/cn/g3soft/fmsapi/config/AuthProperties.java) - [JwtAuthFilter.java](file://fms-api/src/main/java/cn/g3soft/fmsapi/config/JwtAuthFilter.java) - [AuthController.java](file://fms-api/src/main/java/cn/g3soft/fmsapi/controller/AuthController.java) - [AuthService.java](file://fms-api/src/main/java/cn/g3soft/fmsapi/service/AuthService.java) - [AuthenticationException.java](file://fms-api/src/main/java/cn/g3soft/fmsapi/exception/AuthenticationException.java) - [JwtUtilsTests.java](file://fms-api/src/test/java/cn/g3soft/fmsapi/utils/JwtUtilsTests.java)目录
简介
本文件面向FMS后端的安全认证子系统,聚焦基于JWT的无状态认证方案。文档围绕以下目标展开:
- 解释JwtAuthFilter过滤器的工作流程与拦截策略
- 说明令牌生成、校验与刷新机制
- 阐述AuthProperties配置类与安全参数管理
- 描述JwtUtils工具类的核心能力(解析、用户信息提取、权限验证)
- 给出过期处理、防重放攻击等安全考量与最佳实践
项目结构
安全认证相关代码集中在fms-api模块中,采用分层组织:
- 配置层:AuthProperties负责读取并绑定安全相关配置项
- 过滤层:JwtAuthFilter在请求进入控制器前进行鉴权
- 控制层:AuthController暴露登录、登出、刷新等接口
- 服务层:AuthService封装认证业务逻辑(如会话管理、权限加载)
- 异常层:AuthenticationException统一认证失败异常
- 工具层:JwtUtils提供JWT编解码与校验能力(通过测试用例可见其使用方式)
graph TB
Client["客户端"] --> Filter["JwtAuthFilter<br/>请求前置鉴权"]
Filter --> Controller["AuthController<br/>登录/刷新/登出"]
Controller --> Service["AuthService<br/>认证业务逻辑"]
Service --> Utils["JwtUtils<br/>令牌解析/校验"]
Service --> Config["AuthProperties<br/>安全参数配置"]
Service --> DB["数据源/缓存<br/>用户与权限"]
图表来源
章节来源
核心组件
- JwtAuthFilter:在Servlet过滤器链中对每个请求进行JWT校验,决定是否放行或拒绝
- AuthController:对外暴露认证相关HTTP接口,接收登录凭证并返回令牌
- AuthService:实现认证核心流程,包括用户校验、权限装配、令牌签发与刷新
- AuthProperties:集中管理JWT密钥、过期时间、白名单路径等安全参数
- JwtUtils:提供令牌的生成、解析、签名校验与载荷提取
- AuthenticationException:统一抛出认证失败异常,便于全局异常处理
章节来源
- JwtAuthFilter.java
- AuthController.java
- AuthService.java
- AuthProperties.java
- AuthenticationException.java
架构总览
下图展示了从浏览器发起请求到服务端完成鉴权的整体流程,以及关键组件间的交互关系。
sequenceDiagram
participant C as "客户端"
participant F as "JwtAuthFilter"
participant A as "AuthController"
participant S as "AuthService"
participant U as "JwtUtils"
participant P as "AuthProperties"
C->>F : "携带Authorization头发起请求"
F->>F : "匹配白名单/忽略路径"
alt "需要鉴权"
F->>U : "解析并校验JWT"
U-->>F : "有效载荷/错误"
alt "令牌无效或过期"
F-->>C : "401/403响应"
else "令牌有效"
F->>S : "加载用户上下文/权限"
S-->>F : "上下文对象"
F->>A : "放行至控制器"
A-->>C : "业务响应"
end
else "白名单路径"
F->>A : "直接放行"
A-->>C : "业务响应"
end
图表来源
详细组件分析
JwtAuthFilter 过滤器
职责与行为
- 拦截所有入站请求,判断是否命中白名单或静态资源
- 从请求头中提取JWT令牌并进行解析与签名校验
- 将解析出的用户信息与权限注入到当前请求上下文,供后续处理器使用
- 对未认证或权限不足请求返回标准错误码
关键点
- 白名单策略:允许匿名访问的路径(如登录、健康检查)
- 令牌位置:通常从Authorization头获取Bearer Token
- 错误处理:捕获解析异常并转换为统一的认证失败响应
flowchart TD
Start(["进入过滤器"]) --> CheckPath["判断是否白名单/静态资源"]
CheckPath --> |是| Pass["放行至控制器"]
CheckPath --> |否| ExtractToken["提取Authorization头中的令牌"]
ExtractToken --> Validate["调用JwtUtils校验令牌"]
Validate --> Valid{"校验通过?"}
Valid --> |否| Deny["返回401/403"]
Valid --> |是| BuildCtx["构建用户上下文/权限"]
BuildCtx --> Next["继续过滤器链/到达控制器"]
图表来源
章节来源
AuthController 控制器
职责与行为
- 提供登录接口:接收用户名/密码,委托AuthService完成认证并签发JWT
- 提供刷新接口:支持基于旧令牌换取新令牌(可结合黑名单/滑动窗口)
- 提供登出接口:使旧令牌失效(可选,取决于是否启用令牌黑名单)
典型交互
- 登录成功返回包含access_token与refresh_token的响应体
- 刷新时校验refresh_token有效性并颁发新的access_token
- 登出时将当前token加入黑名单或标记为已注销
sequenceDiagram
participant C as "客户端"
participant AC as "AuthController"
participant AS as "AuthService"
participant JU as "JwtUtils"
participant AP as "AuthProperties"
C->>AC : "POST /login {username,password}"
AC->>AS : "authenticate(username,password)"
AS->>JU : "generateAccessToken(user, properties)"
JU-->>AS : "access_token"
AS-->>AC : "{access_token, refresh_token}"
AC-->>C : "200 OK"
C->>AC : "POST /refresh {refresh_token}"
AC->>AS : "refresh(refresh_token)"
AS->>JU : "validateAndGenerateNew(token, properties)"
JU-->>AS : "new_access_token"
AS-->>AC : "{access_token}"
AC-->>C : "200 OK"
图表来源
章节来源
AuthService 服务
职责与行为
- 认证主流程:校验用户身份、加载角色与权限、签发令牌
- 刷新流程:校验refresh_token、生成新的access_token
- 会话管理:维护活跃会话列表、支持强制下线与并发控制
- 权限装配:将用户权限集合注入到上下文,供授权决策使用
注意
- 与数据库或缓存交互以获取用户与权限信息
- 与JwtUtils协作完成令牌生命周期管理
- 与AuthProperties配合读取密钥、过期时间等参数
章节来源
AuthProperties 配置类
作用
- 集中管理JWT相关安全参数,如:
- 签名密钥(secret/key)
- access_token与refresh_token过期时间
- 白名单路径列表
- 是否启用黑名单/撤销机制
- 最大会话数、并发限制等
使用方式
- 通过配置文件(如application.yaml)注入属性
- 在过滤器与服务中读取配置,驱动鉴权与令牌策略
章节来源
JwtUtils 工具类
核心功能
- 生成access_token与refresh_token
- 解析并校验JWT签名与有效期
- 从载荷中提取用户标识、角色与权限
- 支持刷新令牌的重放防护(如一次性使用或短期有效)
测试覆盖
- JwtUtilsTests验证了令牌的生成、解析与基本校验逻辑
章节来源
依赖分析
组件间耦合关系如下:
- JwtAuthFilter依赖JwtUtils进行令牌校验,依赖AuthProperties决定白名单策略
- AuthController依赖AuthService完成认证业务
- AuthService依赖JwtUtils进行令牌签发与校验,依赖AuthProperties读取安全参数
- 所有组件通过统一的AuthenticationException对外暴露认证失败语义
graph LR
Filter["JwtAuthFilter"] --> Utils["JwtUtils"]
Filter --> Props["AuthProperties"]
Controller["AuthController"] --> Service["AuthService"]
Service --> Utils
Service --> Props
Service --> DB["用户/权限存储"]
图表来源
章节来源
性能考虑
- 令牌校验开销:尽量将高频校验逻辑(如签名验证)优化为本地计算;必要时引入缓存减少重复查询
- 会话管理:活跃会话表/缓存需设计合理的索引与淘汰策略,避免内存膨胀
- 刷新令牌:建议设置较短的access_token过期时间与较长的refresh_token周期,降低频繁刷新带来的压力
- 白名单与静态资源:尽早放行以减少过滤器链开销
- 并发控制:限制单用户并发会话数,防止资源滥用
故障排查指南
常见问题与定位
- 401 未认证:检查Authorization头是否正确携带Bearer Token;确认白名单配置是否误拦截
- 403 权限不足:检查用户角色与权限是否已正确加载;确认接口是否需要特定权限
- 令牌过期:调整access_token过期时间或实现自动刷新;检查客户端是否在过期前刷新
- 刷新失败:检查refresh_token是否已被使用或撤销;确认黑名单机制是否生效
- 签名错误:核对AuthProperties中的密钥是否与签发端一致
定位步骤
- 查看过滤器日志:确认是否进入鉴权分支、令牌解析结果
- 检查服务层日志:确认用户与权限加载是否成功
- 复现最小用例:构造仅含必要字段的请求,逐步缩小问题范围
章节来源
结论
本系统采用JWT无状态认证,结合过滤器前置鉴权与统一异常处理,实现了清晰的鉴权边界与可扩展的权限模型。通过AuthProperties集中管理安全参数,JwtUtils提供稳定的令牌处理能力,AuthService串联认证与会话管理。建议在部署时严格管理密钥、合理设置过期时间、启用刷新与黑名单机制,并结合监控与审计提升安全性与可观测性。
附录
- 安全配置最佳实践
- 使用强随机密钥并定期轮换
- 区分access_token与refresh_token的过期策略
- 启用HTTPS传输,防止中间人攻击
- 记录登录与操作日志,便于审计与溯源
- 常见安全问题防护
- 防重放攻击:对敏感接口增加nonce/time-window校验或使用一次性refresh_token
- 会话劫持:绑定设备指纹或IP段(谨慎使用),加强Cookie/Token存储安全
- 暴力破解:对登录接口实施限流与验证码
- 越权访问:在服务层进行细粒度权限校验,不仅依赖前端控制