Spring Security JWT认证配置致Postman带Bearer令牌返回403错误
问题分析与解决方案
1. JWT有效性校验逻辑完全反转(核心问题)
在JwtService的isTokenValid方法中,令牌过期的判断逻辑写反了:
public boolean isTokenValid(String token, UserDetails userDetails) { final String username = extractUsername(token); // 错误:仅当令牌过期时才判定有效,与预期完全相反 return(username.equals(userDetails.getUsername())) && isTokenExpired(token); }
isTokenExpired方法返回true代表令牌已过期,当前逻辑导致只有过期的令牌才会被认为有效,未过期的合法令牌无法通过校验,进而无法设置认证上下文,触发403错误。
修复代码:
public boolean isTokenValid(String token, UserDetails userDetails) { final String username = extractUsername(token); // 修正为:用户名匹配 且 令牌未过期 return(username.equals(userDetails.getUsername())) && !isTokenExpired(token); }
2. 请求链执行逻辑遗漏
JwtAuthenticationFilter中,filterChain.doFilter(request, response)被嵌套在if(userEmail != null && ...)代码块内,导致当userEmail为空或已存在认证信息时,请求链无法继续执行,请求被拦截返回403。
修复代码:
@Override protected void doFilterInternal( @NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull FilterChain filterChain ) throws ServletException, IOException { final String authHeader = request.getHeader(AUTHORIZATION); final String jwt; final String userEmail; if(authHeader == null || !authHeader.startsWith("Bearer ")){ filterChain.doFilter(request, response); return; } jwt = authHeader.substring(7); userEmail = jwtService.extractUsername(jwt); if(userEmail != null && SecurityContextHolder.getContext().getAuthentication() == null){ UserDetails userDetails = this.userDetailsService.loadUserByUsername(userEmail); if(jwtService.isTokenValid(jwt, userDetails)){ UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken( userDetails, null, userDetails.getAuthorities() ); authToken.setDetails( new WebAuthenticationDetailsSource().buildDetails(request) ); SecurityContextHolder.getContext().setAuthentication(authToken); } } // 确保所有分支都会执行请求链,避免请求被拦截 filterChain.doFilter(request, response); }
3. 额外检查项
- 用户权限配置:确保
User类正确实现UserDetails接口,且Role枚举实现GrantedAuthority:
同时public enum Role implements GrantedAuthority { USER, ADMIN; @Override public String getAuthority() { return "ROLE_" + this.name(); } }User类的getAuthorities()方法需返回权限集合:@Override public Collection<? extends GrantedAuthority> getAuthorities() { return Collections.singletonList(role); } - 令牌过期时间:当前令牌有效期为24分钟,测试时确保令牌未过期,可调整为
1000 * 60 * 60 * 24(24小时)延长有效期。
内容的提问来源于stack exchange,提问作者Mr Williams
相关产品推荐
相关产品推荐

