JWT 认证过滤器技术文档
1. 模块概述
JWT 认证过滤器是系统安全模块的核心组件,用于验证用户请求中的 JWT Token 并设置认证信息到 SecurityContextHolder 中。该过滤器基于 Spring Security 实现,支持从请求头或 URL 参数中提取 Token,验证其有效性,并从 Redis 中获取用户信息。
2. 核心功能
- 白名单验证:检查请求路径是否在白名单内,白名单内的路径直接放行
- Token 提取:支持从 Authorization 头或 URL 参数中提取 JWT Token
- Token 验证:验证 Token 的有效性和过期时间
- 用户信息获取:从 Redis 中获取用户详细信息
- 认证信息设置:将用户信息设置到 SecurityContextHolder 中,供后续权限验证使用
3. 代码解析
3.1 类定义
java
@Component
@NonNullApi
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
// 类实现
}@Component:将过滤器注册为 Spring 组件@NonNullApi:表示该类的 API 不允许空值extends OncePerRequestFilter:确保过滤器每个请求只执行一次
3.2 核心属性
java
@Resource
private RedisUtil redisUtil; // Redis 工具类,用于获取用户信息
@Resource
private JwtUtil jwtUtil; // JWT 工具类,用于解析和验证 Token
@Resource
private WhiteUrlProperties whiteUrlProperties; // 白名单配置3.3 过滤方法
java
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
// 检查 URL 是否在白名单内
if (isWhiteUrl(request.getServletPath(), whiteUrlProperties.getUrl())) {
chain.doFilter(request, response);
return;
}
// 验证授权信息
if (!StringUtils.hasText(request.getHeader(HttpHeaders.AUTHORIZATION))) {
chain.doFilter(request, response);
return;
}
// 解析 Token 并验证用户信息
LoginUserInfo loginUserInfo = authenticate(request);
// 设置认证信息
setAuthentication(Objects.requireNonNull(loginUserInfo));
// 放行
chain.doFilter(request, response);
}3.4 Token 认证方法
java
@Nullable
private LoginUserInfo authenticate(@NotNull HttpServletRequest request) {
// 优先从 Authorization Header 获取
String token = null;
String authorization = request.getHeader(HttpHeaders.AUTHORIZATION);
if (StringUtils.hasText(authorization) && authorization.startsWith(Constants.TOKEN_PREFIX)) {
token = authorization.substring(Constants.TOKEN_PREFIX.length()); // 去除 "Bearer " 前缀
}
// 如果 Header 中没有,则尝试从 URL 参数获取(如 ?access_token=xxx)
if (!StringUtils.hasText(token)) {
token = request.getParameter(Constants.ACCESS_TOKEN);
}
// 如果仍无 token,返回 null(不认证)
if (!StringUtils.hasText(token)) {
return null;
}
Claims claims = jwtUtil.parseToken(token);
if (Objects.isNull(claims)) {
throw new ZsException("Invalid token");
}
String loginInfo = claims.getSubject();
Object jsonLoginUserInfo = redisUtil.get(loginInfo);
return JSONUtil.toBean(JSONUtil.parseObj(jsonLoginUserInfo), LoginUserInfo.class);
}3.5 认证信息设置方法
java
private void setAuthentication(@NotNull LoginUserInfo loginUserInfo) {
// 获取权限信息封装到 Authentication 中
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
loginUserInfo, null, loginUserInfo.getAuthorities()
);
// 存入 SecurityContextHolder
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}3.6 白名单验证方法
java
private final AntPathMatcher antPathMatcher = new AntPathMatcher();
private boolean isWhiteUrl(String requestPath, List<String> whiteUrls) {
for (String whiteUrl : whiteUrls) {
if (antPathMatcher.match(whiteUrl, requestPath)) {
return true;
}
}
return false;
}- 使用
AntPathMatcher进行路径匹配,支持通配符(如/api/**) - 遍历白名单,只要匹配到一个白名单路径就返回 true
4. 认证流程
- 请求到达过滤器:客户端发送请求到服务器,经过 JwtAuthenticationTokenFilter
- 白名单检查:检查请求路径是否在白名单内,是则直接放行
- Token 提取:从 Authorization 头或 URL 参数中提取 JWT Token
- Token 验证:使用 JwtUtil 验证 Token 的有效性
- 用户信息获取:从 Redis 中获取用户详细信息
- 认证信息设置:将用户信息设置到 SecurityContextHolder 中
- 请求放行:将请求传递给下一个过滤器或资源处理器
5. 配置说明
5.1 白名单配置
在 application.yml 中配置白名单路径:
yaml
zs:
security:
white-url:
url:
- /api/login
- /api/register
- /api/public/**5.2 JWT 配置
在 application.yml 中配置 JWT 相关参数:
yaml
zs:
jwt:
secret: your_jwt_secret_key
expiration: 3600000 # Token 有效期,单位毫秒
token-prefix: Bearer # Token 前缀5.3 Redis 配置
确保 Redis 服务正常运行,并在 application.yml 中配置 Redis 连接信息:
yaml
spring:
redis:
host: localhost
port: 6379
password: your_redis_password
database: 06. 使用方法
6.1 在 Spring Security 配置中注册过滤器
java
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
@Resource
private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
// 其他配置
.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
}6.2 客户端使用示例
6.2.1 使用 Authorization 头
javascript
fetch('https://api.example.com/protected-resource', {
headers: {
'Authorization': 'Bearer your_jwt_token'
}
})6.2.2 使用 URL 参数
javascript
fetch('https://api.example.com/protected-resource?access_token=your_jwt_token')7. 注意事项
- Token 有效期:确保 Redis 中存储的用户信息有效期与 JWT Token 有效期一致
- 白名单配置:合理配置白名单,避免将需要认证的路径加入白名单
- 异常处理:过滤器抛出的异常会被 Spring Security 的异常处理器捕获,需要配置相应的异常处理逻辑
- 性能考虑:过滤器每个请求都会执行,确保其逻辑高效,避免耗时操作
- 安全考虑:确保 JWT 密钥的安全性,避免泄露
8. 扩展建议
- 添加 Token 刷新机制:支持在 Token 即将过期时自动刷新
- 添加 Token 黑名单:支持将已注销的 Token 加入黑名单,防止恶意使用
- 添加请求限流:对频繁请求的 IP 进行限流,防止暴力破解
- 添加日志记录:记录 Token 验证过程,便于调试和审计
- 支持多 Token 类型:支持不同类型的 Token,如访问 Token 和刷新 Token