You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 04:07:20