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

带@Component注解的自定义额外AuthenticationProvider引发无限循环

问题分析与解决思路

你的问题核心是:添加NotUsedFakeAuthenticationProvider作为@Component后,认证失败触发无限循环,移除该注解则恢复正常,但你需要保留这个Provider用于其他业务。

根本原因

Spring Security会自动将所有标注@Component的AuthenticationProvider Bean注册到所有AuthenticationManager实例中——包括你手动构建的那个。虽然NotUsedFakeAuthenticationProvider的supports方法只处理FakeAuthenticationToken2,不会介入FakeAuthenticationToken的认证流程,但此时ProviderManager(AuthenticationManager的默认实现)在处理认证时会遍历所有已注册的Provider:

  1. 第一个Provider(FakeAuthenticationProvider)抛出InsufficientAuthenticationException,被捕获并记录为最后异常
  2. 遍历到NotUsedFakeAuthenticationProvider时,因不支持FakeAuthenticationToken被跳过
  3. 最终抛出的仍是InsufficientAuthenticationException,但这个遍历过程导致异常处理逻辑发生变化:原本应由自定义过滤器的失败处理器处理的异常,被ExceptionTranslationFilter拦截,触发重定向到登录页面;而你的自定义过滤器又会拦截登录请求的POST提交,再次触发认证失败,形成无限循环。

同时,你的自定义过滤器未设置自定义失败处理器,默认的SimpleUrlAuthenticationFailureHandler会重定向到登录页面,进一步加剧了循环。

解决方案

方案1:手动控制AuthenticationManager的Provider注册

修改你手动构建AuthenticationManager的代码,清除Spring自动添加的所有Provider,只保留你需要的FakeAuthenticationProvider:

@Bean
public AuthenticationManager getAuthenticationManager(HttpSecurity http, FakeAuthenticaitonProvider fakeAuthenticaitonProvider) throws Exception {
    AuthenticationManagerBuilder authenticationManagerBuilder = http.getSharedObject(AuthenticationManagerBuilder.class);
    // 清除自动注册的所有Provider
    authenticationManagerBuilder.getProviders().clear();
    // 只添加当前过滤器需要的Provider
    authenticationManagerBuilder.authenticationProvider(fakeAuthenticaitonProvider);
    return authenticationManagerBuilder.build();
}

这样,你手动构建的AuthenticationManager只会包含FakeAuthenticationProvider,不会被NotUsedFakeAuthenticationProvider干扰,认证失败后会正常触发自定义过滤器的失败处理器。

方案2:给自定义过滤器设置自定义失败处理器

直接指定认证失败后的跳转逻辑,避免默认的登录页面重定向:

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http, AuthenticationManager authenticationManager) throws Exception {

    final FakeAuthenticationFilter fakeAuthenticationFilter = new FakeAuthenticationFilter();
    fakeAuthenticationFilter.setAuthenticationManager(authenticationManager);
    // 设置自定义失败处理器,跳转到错误页面
    fakeAuthenticationFilter.setAuthenticationFailureHandler((request, response, exception) -> {
        response.sendRedirect("/error");
    });

    http    .addFilterBefore(fakeAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
            .authorizeHttpRequests((authorize) -> authorize
                    .requestMatchers("/error").permitAll() // 允许匿名访问错误页面
                    .anyRequest().authenticated()
            )
            .formLogin(withDefaults());
    return http.build();
}

同时要确保错误页面/error允许匿名访问,否则跳转后会再次触发认证流程。

方案3:限定NotUsedFakeAuthenticationProvider的注册范围

如果NotUsedFakeAuthenticationProvider只在特定业务场景中使用,不要用@Component自动注册,而是在需要它的地方手动创建实例,或者通过@Bean注解仅注册到特定的AuthenticationManager中:

// 移除NotUsedFakeAuthenticationProvider上的@Component注解
public class NotUsedFakeAuthenticaitonProvider implements AuthenticationProvider {
    // ... 原有代码
}

// 在需要使用它的配置类中手动注册
@Configuration
public class OtherSecurityConfiguration {
    @Bean
    public AuthenticationManager otherAuthenticationManager(HttpSecurity http) throws Exception {
        AuthenticationManagerBuilder builder = http.getSharedObject(AuthenticationManagerBuilder.class);
        builder.authenticationProvider(new NotUsedFakeAuthenticaitonProvider());
        return builder.build();
    }
}

这样既保留了该Provider的业务用途,又不会干扰主认证流程的AuthenticationManager。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 04:50:55