AuthenticationFilter是继承OncePerRequestFilter的,但是AuthenticationFilter抛出的异常,没有在ExceptionTranslationFilter里面被捕获,而是到了ServletInitialHandler被捕获

AuthenticationFilter 里抛出了一个AuthenticationException,没有被ExceptionTranslationFilter里面被捕获,进入到AuthenticationEntryPoint,而是被ServletInitialHandler捕获,跳转到/error 路径。我是一个前后端分离的项目的,我配置里关闭了网页登录相关的,配置如下

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
        return httpSecurity.authorizeHttpRequests(
                requests -> requests
                        .requestMatchers(springSecurityProperties.getPermitAllPaths()).permitAll()
                        .anyRequest().authenticated()
                )
                .authenticationManager(authenticationManager())

                .formLogin(AbstractHttpConfigurer::disable)
                .logout(AbstractHttpConfigurer::disable)
                .sessionManagement(AbstractHttpConfigurer::disable)
                .httpBasic(AbstractHttpConfigurer::disable)
                .csrf(AbstractHttpConfigurer::disable)
                .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))

                .cors(cors -> cors.configurationSource(corsConfigurationSource()))
                .addFilterBefore(authenticationFilter, UsernamePasswordAuthenticationFilter.class)
                .exceptionHandling(exception ->
                        exception.accessDeniedHandler(new IrsAccessDeniedHandler())
                                .authenticationEntryPoint(new IrsAuthenticationEntryPoint())
                )
                .build();
    }

AuthenticationFilter 是继承OncePerRequestFilter的,也放到了UsernamePasswordAuthenticationFilter之前addFilterBefore(authenticationFilter, UsernamePasswordAuthenticationFilter.class)
可是在AuthenticationFilter 抛出的AuthenticationException 确定没能通过IrsAuthenticationEntryPoint捕获到,导致无法正确处理异常,请问需要怎么做才能通过 IrsAuthenticationEntryPoint 捕获到 AuthenticationFilter里的异常

这个问题可能有几个原因:

  1. 检查异常处理配置的位置,exceptionHandling 应该在 build() 之前配置。从你的代码看位置是对的。
  2. 确认 /error 路径是否在 permitAllPaths 中。如果是的话,可能会影响自定义异常处理。
  3. 最常见的原因是自定义异常处理器的优先级问题。Spring Boot 的默认错误处理可能覆盖了自定义处理。尝试添加以下配置:
@Configuration
public class WebServerConfiguration {
    @Bean
    public WebServerFactoryCustomizer<ConfigurableWebServerFactory> webServerFactoryCustomizer() {
        return factory -> factory.setPort(8080);
    }

    @Bean
    public ErrorPageRegistrar errorPageRegistrar() {
        return registry -> registry.addErrorPages(new ErrorPage(HttpStatus.UNAUTHORIZED, "/401"));
    }
}
  1. 在 application.properties/yaml 中禁用默认错误页面:
server.error.whitelabel.enabled=false
  1. 检查你的自定义异常处理类实现:
@Component
public class IrsAuthenticationEntryPoint implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response,
                        AuthenticationException authException) throws IOException {
        response.setContentType("application/json;charset=UTF-8");
        response.setStatus(HttpStatus.UNAUTHORIZED.value());
        
        // 确保这里直接写响应,而不是重定向
        response.getWriter().write("{\"code\":401,\"message\":\"未授权\"}");
    }
}
  1. 可以尝试在 SecurityFilterChain 中添加调试日志:
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
    return httpSecurity
        // ... 其他配置 ...
        .exceptionHandling(exception -> {
            exception
                .accessDeniedHandler((request, response, ex) -> {
                    System.out.println("访问被拒绝: " + ex.getMessage());
                    new IrsAccessDeniedHandler().handle(request, response, ex);
                })
                .authenticationEntryPoint((request, response, ex) -> {
                    System.out.println("认证异常: " + ex.getMessage());
                    new IrsAuthenticationEntryPoint().commence(request, response, ex);
                });
        })
        .build();
}