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

使用authenticationManager.authenticate()时出现StackOverflowError的解决方法

解决AuthenticationManager.authenticate()抛出StackOverflowError的问题

问题场景

调用authenticationManager.authenticate()方法时触发StackOverflowError,未继承已废弃的WebSecurityConfigurerAdapter,当前SecurityConfig配置如下:

@Configuration
@EnableWebSecurity
public class SecurityConfig{

    @Bean
    public UserDetailsService userDetailsService() {
        return new CustomUserDetailsService();
    }

    @Bean
    @Order(1)
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.httpBasic().disable().csrf().disable().sessionManagement()
                .and().authorizeRequests()
                .antMatchers("/**").permitAll()
                .anyRequest().authenticated().and().csrf().disable();
        http
                .logout()
                .invalidateHttpSession(true)
                .logoutSuccessHandler(new HttpStatusReturningLogoutSuccessHandler(HttpStatus.OK));
        return http.build();
    }

    @Bean
    @Order(0)
    public SecurityFilterChain resources(HttpSecurity http) throws Exception {
        http.requestMatchers((matchers) -> matchers.antMatchers("*.bundle.*"))
                .authorizeHttpRequests((authorize) -> authorize.anyRequest().permitAll())
                .requestCache().disable()
                .securityContext().disable()
                .sessionManagement().disable();

        return http.build();
    }

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

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

错误日志

2022-07-18 17:26:52.277 ERROR 12368 --- [nio-8080-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler dispatch failed; nested exception is java.lang.StackOverflowError] with root cause

java.lang.StackOverflowError: null
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.3.21.jar:5.3.21]
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208) ~[spring-aop-5.3.21.jar:5.3.21]
    at com.sun.proxy.$Proxy111.authenticate(Unknown Source) ~[na:na]
    at jdk.internal.reflect.GeneratedMethodAccessor60.invoke(Unknown Source) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.3.21.jar:5.3.21]
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208) ~[spring-aop-5.3.21.jar:5.3.21]
    at com.sun.proxy.$Proxy111.authenticate(Unknown Source) ~[na:na]
    at jdk.internal.reflect.GeneratedMethodAccessor60.invoke(Unknown Source) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.3.21.jar:5.3.21]
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208) ~[spring-aop-5.3.21.jar:5.3.21]
    at com.sun.proxy.$Proxy111.authenticate(Unknown Source) ~[na:na]
    at jdk.internal.reflect.GeneratedMethodAccessor60.invoke(Unknown Source) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]

*continues till stack overflow*

认证Controller代码

@CrossOrigin
@RestController
public class UserController {

    @Autowired
    AuthenticationManager authenticationManager;

    @Autowired
    CustomUserService userService;

    @Autowired
    JwtTokenProvider jwtTokenProvider;

    @PostMapping("/login")
    public ResponseEntity<Map<Object, Object>> login(@RequestBody CustomUserLoginDto userDto) {
        try {
            String email = userDto.getEmail();
            Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(email, userDto.getPassword()));
            SecurityContextHolder.getContext().setAuthentication(authentication);
            String token = jwtTokenProvider.createToken(email);
            Map<Object, Object> model = new HashMap<>();
            model.put("username", email);
            model.put("token", token);
            return ResponseEntity.ok(model);
        } catch (AuthenticationException e) {
            throw new BadCredentialsException("Invalid email/password supplied");
        }
    }

    @PostMapping("/register")
    public CustomUser register(@RequestBody CustomUserCreateDto userDto) {
        return userService.saveUser(userDto);
    }
}

解决方案

这个问题的核心是手动定义的AuthenticationManager Bean和Spring Security内部的AuthenticationManager形成了循环代理,导致调用authenticate时无限递归触发栈溢出。

修复步骤

  1. 移除手动定义的AuthenticationManager Bean
    删掉SecurityConfig中以下代码:

    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }
    
  2. 在SecurityFilterChain中配置认证逻辑
    通过HttpSecurity的getSharedObject获取AuthenticationManagerBuilder,绑定UserDetailsService和PasswordEncoder,让Spring自动生成正确的AuthenticationManager实例:
    修改后的SecurityConfig:

    @Configuration
    @EnableWebSecurity
    public class SecurityConfig{
    
        @Bean
        public UserDetailsService userDetailsService() {
            return new CustomUserDetailsService();
        }
    
        @Bean
        @Order(1)
        public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
            // 绑定用户认证逻辑
            AuthenticationManagerBuilder auth = http.getSharedObject(AuthenticationManagerBuilder.class);
            auth.userDetailsService(userDetailsService())
                .passwordEncoder(bCryptPasswordEncoder());
            
            http.httpBasic().disable()
                .csrf().disable()
                .sessionManagement()
                .and()
                .authorizeRequests()
                .antMatchers("/**").permitAll()
                .anyRequest().authenticated()
                .and()
                .logout()
                .invalidateHttpSession(true)
                .logoutSuccessHandler(new HttpStatusReturningLogoutSuccessHandler(HttpStatus.OK));
            return http.build();
        }
    
        @Bean
        @Order(0)
        public SecurityFilterChain resources(HttpSecurity http) throws Exception {
            http.requestMatchers((matchers) -> matchers.antMatchers("*.bundle.*"))
                .authorizeHttpRequests((authorize) -> authorize.anyRequest().permitAll())
                .requestCache().disable()
                .securityContext().disable()
                .sessionManagement().disable();
    
            return http.build();
        }
    
        @Bean
        public PasswordEncoder bCryptPasswordEncoder() {
            return new BCryptPasswordEncoder();
        }
    }
    
  3. Controller中直接注入AuthenticationManager
    不需要额外配置,Spring会自动将正确的AuthenticationManager实例注入到Controller中,原Controller代码无需修改。

这样就能解决循环代理导致的StackOverflowError问题,让authenticate方法正常执行用户认证逻辑。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 02:39:09