Spring Boot中AuthenticationEntryPoint未处理部分JWT认证异常
Spring Boot API网关JWT认证异常统一处理方案
问题根源
JwtAuthenticationEntryPoint仅处理认证入口阶段的异常(如InsufficientAuthenticationException),而ExpiredJwtException、MalformedJwtException等JWT解析异常是在过滤器链中抛出的,默认会被Spring Security的内置异常机制拦截处理,无法触发自定义EntryPoint。要实现全量异常自定义处理,需要结合全局异常处理器和过滤器异常捕获来覆盖整个链路。
解决方案步骤
1. 自定义全局异常处理器
通过@RestControllerAdvice统一捕获所有认证、权限及JWT相关异常,返回标准化API响应:
@RestControllerAdvice public class GlobalExceptionHandler { // 处理Spring Security认证异常 @ExceptionHandler(AuthenticationException.class) public ResponseEntity<ApiResponse> handleAuthExceptions(AuthenticationException e) { ApiResponse response = new ApiResponse(HttpStatus.UNAUTHORIZED.value(), "认证失败:" + e.getMessage()); return new ResponseEntity<>(response, HttpStatus.UNAUTHORIZED); } // 处理权限不足异常 @ExceptionHandler(AccessDeniedException.class) public ResponseEntity<ApiResponse> handleAccessDenied(AccessDeniedException e) { ApiResponse response = new ApiResponse(HttpStatus.FORBIDDEN.value(), "权限不足:" + e.getMessage()); return new ResponseEntity<>(response, HttpStatus.FORBIDDEN); } // 专门处理JWT解析类异常 @ExceptionHandler({ExpiredJwtException.class, MalformedJwtException.class, SignatureException.class}) public ResponseEntity<ApiResponse> handleJwtErrors(RuntimeException e) { ApiResponse response = new ApiResponse(HttpStatus.UNAUTHORIZED.value(), "JWT令牌无效:" + e.getMessage()); return new ResponseEntity<>(response, HttpStatus.UNAUTHORIZED); } // 统一API响应体 public static class ApiResponse { private int code; private String message; public ApiResponse(int code, String message) { this.code = code; this.message = message; } // Getter & Setter public int getCode() { return code; } public void setCode(int code) { this.code = code; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } } }
2. 修改JWT过滤器捕获异常
在JWT解析过程中主动捕获异常,可选择直接抛出自定义异常(交给全局处理器)或转换为Spring Security认证异常:
@Component public class JwtAuthenticationFilter extends OncePerRequestFilter { private final JwtTokenProvider jwtTokenProvider; public JwtAuthenticationFilter(JwtTokenProvider jwtTokenProvider) { this.jwtTokenProvider = jwtTokenProvider; } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String token = extractTokenFromRequest(request); if (StringUtils.hasText(token)) { try { // 解析JWT并设置认证上下文 Authentication auth = jwtTokenProvider.getAuthentication(token); SecurityContextHolder.getContext().setAuthentication(auth); } catch (ExpiredJwtException e) { throw new BadCredentialsException("JWT令牌已过期"); } catch (MalformedJwtException | SignatureException e) { throw new BadCredentialsException("JWT令牌格式错误或签名无效"); } } filterChain.doFilter(request, response); } private String extractTokenFromRequest(HttpServletRequest request) { String bearerToken = request.getHeader("Authorization"); if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) { return bearerToken.substring(7); } return null; } }
3. 配置Spring Security链路
确保自定义过滤器、EntryPoint和全局处理器协同工作:
@Configuration @EnableWebSecurity public class SecurityConfig { private final JwtAuthenticationFilter jwtAuthFilter; private final JwtAuthenticationEntryPoint authEntryPoint; private final AccessDeniedHandler accessDeniedHandler; public SecurityConfig(JwtAuthenticationFilter jwtAuthFilter, JwtAuthenticationEntryPoint authEntryPoint, AccessDeniedHandler accessDeniedHandler) { this.jwtAuthFilter = jwtAuthFilter; this.authEntryPoint = authEntryPoint; this.accessDeniedHandler = accessDeniedHandler; } @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.csrf(csrf -> csrf.disable()) .authorizeHttpRequests(auth -> auth .requestMatchers("/api/auth/**").permitAll() .anyRequest().authenticated()) .exceptionHandling(ex -> ex .authenticationEntryPoint(authEntryPoint) .accessDeniedHandler(accessDeniedHandler)) .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class); return http.build(); } }
关键说明
- 全局异常处理器覆盖了所有异常场景,包括过滤器中抛出的JWT异常和Security内置异常,确保返回格式统一。
- JWT过滤器中捕获异常后转换为
AuthenticationException子类,既可以触发自定义EntryPoint,也能被全局处理器捕获,避免默认异常处理逻辑介入。 - 若不需要EntryPoint,可直接在过滤器中通过
response输出JSON响应,但全局处理器的方式更利于统一维护。
内容的提问来源于stack exchange,提问作者Tvrsier
相关产品推荐
相关产品推荐

