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

Autowired注入AuthenticationManager为何抛出StackOverflowError?

集成JWT的Spring Boot应用中AuthenticationManager注入导致StackOverflowError的解决方法

问题场景

开发集成JWT安全机制的Spring Boot应用时,计划通过Spring Security的AuthenticationManager实现身份验证。在配置类中创建了AuthenticationManager Bean,在RestController中通过@Autowired注入后,调用时抛出StackOverflowError。

代码示例

Controller类

@RestController
public class AuthenticationController {
    @Autowired
    AuthenticationManager authenticationManager;

    @GetMapping("/sign-in")
    public String signIn() {
        System.out.println(authenticationManager);
        return "Hello World";
    }
}

Configuration类

@Configuration
public class JwtConfiguration {
    @Bean
    public AuthenticationManager authenticationManager(
            final AuthenticationConfiguration authenticationConfiguration) throws Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }

    @Bean
    public SecurityFilterChain configure(final HttpSecurity http) throws Exception {
        http.authorizeHttpRequests()
                .requestMatchers("/sign-in").permitAll();
        return http.build();
    }
}

错误信息

java.lang.StackOverflowError: null
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:163) ~[spring-aop-6.0.7.jar:6.0.7]
    at jdk.proxy2/jdk.proxy2.$Proxy58.toString(Unknown Source) ~[na:na]
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:577) ~[na:na]
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) ~[spring-aop-6.0.7.jar:6.0.7]
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:211) ~[spring-aop-6.0.7.jar:6.0.7]
    at jdk.proxy2/jdk.proxy2.$Proxy58.toString(Unknown Source) ~[na:na]
    ...(重复递归调用)

原因分析

问题根源在于自定义的AuthenticationManager Bean与Spring Security自动配置的Bean产生了代理嵌套:

  • AuthenticationConfiguration.getAuthenticationManager()返回的对象本身已经是Spring AOP代理对象
  • 将该代理对象再次注册为自定义Bean后,Spring会为这个Bean再次生成代理,形成代理嵌套
  • 当调用System.out.println(authenticationManager)时,触发了代理对象的toString()方法,导致代理之间无限递归调用,最终抛出栈溢出错误

解决方案

方案1:移除自定义的AuthenticationManager Bean

Spring Security已经通过AuthenticationConfiguration自动配置了AuthenticationManager Bean,无需手动注册。直接在Controller中注入即可:

修改后的JwtConfiguration类:

@Configuration
public class JwtConfiguration {
    @Bean
    public SecurityFilterChain configure(final HttpSecurity http) throws Exception {
        http.authorizeHttpRequests()
                .requestMatchers("/sign-in").permitAll();
        return http.build();
    }
}

方案2:避免触发代理的无限递归(可选)

如果确实需要保留自定义Bean,且要打印AuthenticationManager,可以获取代理的目标对象后再打印:

import org.springframework.aop.support.AopUtils;

@GetMapping("/sign-in")
public String signIn() {
    try {
        AuthenticationManager targetManager = (AuthenticationManager) AopUtils.getTargetObject(authenticationManager);
        System.out.println(targetManager);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return "Hello World";
}

方案3:自定义AuthenticationManager的正确方式(如需扩展)

如果需要自定义AuthenticationManager的逻辑(比如配置自定义UserDetailsService),应该通过SecurityFilterChain关联配置:

@Configuration
public class JwtConfiguration {
    @Autowired
    private UserDetailsService userDetailsService;

    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authConfig) throws Exception {
        AuthenticationManagerBuilder authBuilder = authConfig.getAuthenticationManagerBuilder();
        authBuilder.userDetailsService(userDetailsService)
                   .passwordEncoder(passwordEncoder());
        return authBuilder.build();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public SecurityFilterChain configure(final HttpSecurity http) throws Exception {
        http.authorizeHttpRequests()
                .requestMatchers("/sign-in").permitAll()
                .anyRequest().authenticated()
                .and()
                .authenticationManager(authenticationManager(authConfig));
        return http.build();
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 23:50:31