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

Spring Security 6中InvalidBearerTokenException异常处理问题解决

解决Spring Boot 3 + Spring Security 6中InvalidBearerTokenException异常处理失效问题

问题根源

Spring Security的认证异常(包括InvalidBearerTokenException)是在Filter链阶段抛出的,而@ExceptionHandler注解的处理器仅在DispatcherServlet处理请求的阶段生效。这类Filter层的异常根本无法到达Controller层,因此你的自定义@ExceptionHandler无法捕获到它们。

解决方案

通过自定义AuthenticationEntryPoint来处理Filter链中的认证失败异常,直接在Filter层返回自定义错误响应,无需经过DispatcherServlet。

1. 实现自定义AuthenticationEntryPoint

创建一个类实现AuthenticationEntryPoint接口,重写commence方法来构建并返回自定义错误信息:

@Component
public class CustomAuthEntryPoint implements AuthenticationEntryPoint {

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
        // 构建自定义错误对象
        Error error = new Error()
                .errorCode(Error.ErrorCodeEnum.INVALID_TOKEN)
                .errorDescription(authException.getMessage());

        // 设置响应状态和格式
        response.setStatus(HttpStatus.UNAUTHORIZED.value());
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        
        // 将错误对象序列化为JSON写入响应流
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.writeValue(response.getOutputStream(), error);
    }
}

2. 修改SecurityFilterChain配置

将自定义的AuthenticationEntryPoint配置到SecurityFilterChain中,替换默认的异常处理逻辑:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http, CustomAuthEntryPoint customAuthEntryPoint) throws Exception {
    http.csrf(AbstractHttpConfigurer::disable)
            .authorizeHttpRequests(authorize -> authorize
                    .requestMatchers("/v1/**").permitAll() // 补全权限规则,允许/v1路径无需认证
                    .anyRequest().authenticated())
            .oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()))
            .exceptionHandling(ex -> ex
                    .authenticationEntryPoint(customAuthEntryPoint) // 配置自定义认证异常处理器
                    // 可选:自定义授权失败(无权限)的处理逻辑
                    .accessDeniedHandler((req, res, ex) -> {
                        res.setStatus(HttpStatus.FORBIDDEN.value());
                        res.setContentType(MediaType.APPLICATION_JSON_VALUE);
                        Error error = new Error().errorCode(Error.ErrorCodeEnum.ACCESS_DENIED).errorDescription(ex.getMessage());
                        new ObjectMapper().writeValue(res.getOutputStream(), error);
                    }));
    return http.build();
}

3. 关于原有@ExceptionHandler的说明

你定义的@ExceptionHandler可以保留,用于捕获Controller层手动抛出的AuthenticationException子类异常,但无法处理Filter链阶段的认证异常。

内容的提问来源于stack exchange,提问作者user1428716

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 17:45:14