登录接口触发StackOverflowError,AuthenticationManager递归异常排查
常见问题原因及排查方向
AuthenticationManager Bean配置循环依赖
自定义AuthenticationManager时,若错误地让Bean实例依赖自身,比如配置类中定义的AuthenticationManager Bean,又被自定义AuthenticationProvider、UserDetailsService注入,形成循环引用链。比如这种错误配置:@Bean public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception { return config.getAuthenticationManager(); }同时在自定义Provider中注入了这个Bean,就会触发循环调用。
自定义AuthenticationProvider套娃调用
在自定义AuthenticationProvider的authenticate()方法中,不要调用authenticationManager.authenticate(),这会直接导致无限递归。正确的做法是在Provider内部实现完整的认证逻辑:查询用户、校验凭证等。SecurityFilterChain配置冲突
在配置SecurityFilterChain时,若重复设置AuthenticationManager实例,比如同时在全局Bean和http.authenticationManager()中配置同一个对象,可能引发循环依赖。
具体解决步骤
移除自定义AuthenticationManager Bean
直接通过AuthenticationConfiguration获取默认实例,避免手动定义Bean引发的循环。在需要调用的类中注入:@Autowired private AuthenticationConfiguration authConfig; public void login(LoginRequest request) throws Exception { AuthenticationManager authManager = authConfig.getAuthenticationManager(); authManager.authenticate(new UsernamePasswordAuthenticationToken(request.getUsername(), request.getPassword())); // 后续JWT生成逻辑 }检查自定义AuthenticationProvider实现
确保authenticate()方法内只处理自身的认证逻辑,不要调用AuthenticationManager的认证方法。示例:@Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { String username = authentication.getName(); String password = authentication.getCredentials().toString(); // 从UserRepository查询用户 User user = userRepository.findByUsername(username); if (user != null && passwordEncoder.matches(password, user.getPassword())) { return new UsernamePasswordAuthenticationToken(username, password, user.getAuthorities()); } else { throw new BadCredentialsException("Invalid credentials"); } }清理SecurityFilterChain冗余配置
确保在SecurityFilterChain中不要重复指定AuthenticationManager,让Spring Security自动处理实例注入,比如:@Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.csrf(csrf -> csrf.disable()) .authorizeHttpRequests(auth -> auth .requestMatchers("/auth/**").permitAll() .anyRequest().authenticated() ) .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)); // 不要手动设置authenticationManager,除非明确知道不会引发循环 return http.build(); }
内容的提问来源于stack exchange,提问作者Google Keep

