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

Spring Boot对接Active Directory认证输入错误凭证触发无限循环问题

问题分析

输入错误凭证时触发无限循环并最终导致StackOverflowError,核心原因在于自定义认证管理器的构建方式与Spring Security默认机制冲突,结合ActiveDirectoryLdapAuthenticationProvider的错误处理逻辑,引发了递归调用:

  1. 通过HttpSecurity的AuthenticationManagerBuilder构建认证管理器,容易与全局认证管理器产生循环依赖;
  2. 启用的formLogin默认配置会引入额外的认证过滤器和入口点,与自定义REST登录接口冲突;
  3. convertSubErrorCodesToExceptions开启后,错误码转换逻辑可能触发重复的LDAP连接尝试。

修复方案

1. 调整WebSecurityConfig配置

移除冲突的formLogin配置,改用全局认证管理器构建方式,并将AD认证提供者注册为独立Bean:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

    private static final String DOMAIN = "xxxxxx.net";
    private static final String URL = "ldap://xxxxxxxx:389"; // 移除末尾斜杠,避免URI解析问题

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.csrf(AbstractHttpConfigurer::disable)
                .cors(cors -> cors
                        .configurationSource(request -> {
                            CorsConfiguration corsConfiguration = new CorsConfiguration();
                            corsConfiguration.setAllowedOrigins(List.of("http://localhost:4200"));
                            corsConfiguration.setAllowedMethods(List.of("POST", "PUT", "GET", "DELETE", "OPTIONS"));
                            corsConfiguration.setAllowedHeaders(List.of("Authorization", "Content-Type"));
                            corsConfiguration.setAllowCredentials(true);
                            return corsConfiguration;
                        }))
                .authorizeHttpRequests(authorize -> authorize
                        .requestMatchers("/auth/**").permitAll()
                        .anyRequest().authenticated())
                .sessionManagement(session ->
                        session.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED));
        return http.build();
    }

    // 独立注册AD认证提供者
    @Bean
    public ActiveDirectoryLdapAuthenticationProvider activeDirectoryLdapAuthenticationProvider() {
        ActiveDirectoryLdapAuthenticationProvider adProvider =
                new ActiveDirectoryLdapAuthenticationProvider(DOMAIN, URL);
        adProvider.setConvertSubErrorCodesToExceptions(true);
        adProvider.setUseAuthenticationRequestCredentials(true);
        return adProvider;
    }

    // 通过全局配置获取认证管理器,避免循环依赖
    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authConfig) throws Exception {
        return authConfig.getAuthenticationManager();
    }
}

2. 简化LoginController逻辑

移除手动管理Session的冗余代码,Spring Security会自动处理SecurityContext:

@RestController
@RequestMapping("/auth")
public class LoginController {

    @Autowired
    private AuthenticationManager authenticationManager;

    @PostMapping("/login")
    public ResponseEntity<?> login(@RequestBody Login login, HttpServletRequest request) {
        try {
            UsernamePasswordAuthenticationToken authToken =
                    new UsernamePasswordAuthenticationToken(login.getUser(), login.getPassword());
            authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));

            Authentication auth = authenticationManager.authenticate(authToken);
            SecurityContextHolder.getContext().setAuthentication(auth);

            return ResponseEntity.ok(Map.of("message", "Login Successful"));
        } catch (AuthenticationException e) {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
                    .body(Map.of("error", "Login Failed: " + e.getMessage()));
        }
    }
}

3. 可选:临时禁用错误码转换

如果问题仍存在,可先关闭错误码转换逻辑,验证是否为该功能导致的循环:

adProvider.setConvertSubErrorCodesToExceptions(false);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 05:08:10