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

Spring Security 5.7如何配置LDAP认证同时保留JDBC表单登录

问题根因

Spring Security 5.7+ 组件化配置中,直接调用http.authenticationManager()传入单个认证管理器,会完全覆盖默认支持多认证源轮询的ProviderManager实现,不会自动合并JDBC、LDAP等不同认证逻辑,这就是两种认证方式无法同时生效的核心原因。
旧版WebSecurityConfigurerAdapter配置下,先后调用auth.userDetailsService()和auth.ldapAuthentication()时,框架会自动按顺序把JDBC对应的DaoAuthenticationProvider、LDAP对应的LdapAuthenticationProvider注册到同一个ProviderManager中,按添加顺序轮询实现认证回退。

正确配置方案

不需要手动构建全局AuthenticationManager,直接将两个认证源对应的AuthenticationProvider按优先级注册到Spring容器即可,默认的ProviderManager会自动收集所有Provider按顺序执行,实现LDAP优先、失败回退JDBC的逻辑。
完整配置代码如下:

@Configuration
public class WebSecurityConfig
{
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception
    {
        // @formatter:off
        http.authorizeRequests()
            .mvcMatchers("/services/**", "/resources/**", "/webjars/**").permitAll()
            .anyRequest().authenticated();
        http.httpBasic();
        http.formLogin().permitAll()
            .loginPage("/login")
            .defaultSuccessUrl("/customer/overview", true);
        http.logout().permitAll();

        http.csrf().disable();
        http.headers().frameOptions().disable();
        // 移除手动设置authenticationManager的代码,避免覆盖默认多Provider管理器
        // @formatter:on

        return http.build();
    }

    /**
     * LDAP认证Provider,优先级最高
     */
    @Bean
    @Order(0)
    public LdapAuthenticationProvider ldapAuthenticationProvider(
            BaseLdapPathContextSource ldapContextSource,
            UserDetailsService userDetailsService) {
        // 配置LDAP用户搜索规则,和旧版配置对齐
        BindAuthenticator authenticator = new BindAuthenticator(ldapContextSource);
        authenticator.setUserSearch(new FilterBasedLdapUserSearch(
                "ou=people",
                "(uid={0})",
                ldapContextSource
        ));

        // 配置权限映射
        UserDetailsServiceLdapAuthoritiesPopulator authoritiesPopulator =
                new UserDetailsServiceLdapAuthoritiesPopulator(userDetailsService);

        LdapAuthenticationProvider ldapProvider = new LdapAuthenticationProvider(authenticator, authoritiesPopulator);
        // 如果需要使用自定义的用户上下文映射,直接在此处设置即可,和旧版customLdapUserDetailsContextMapper逻辑一致
        // ldapProvider.setUserDetailsContextMapper(customLdapUserDetailsContextMapper());
        return ldapProvider;
    }

    /**
     * JDBC表单认证Provider,LDAP认证失败后回退执行
     */
    @Bean
    @Order(1)
    public DaoAuthenticationProvider jdbcAuthenticationProvider(
            UserDetailsService userDetailsService,
            PasswordEncoder passwordEncoder) {
        DaoAuthenticationProvider daoProvider = new DaoAuthenticationProvider();
        daoProvider.setUserDetailsService(userDetailsService);
        daoProvider.setPasswordEncoder(passwordEncoder);
        // 关闭用户不存在隐藏逻辑,保证LDAP查无用户时可正常回退到JDBC认证
        daoProvider.setHideUserNotFoundExceptions(false);
        return daoProvider;
    }

    @Bean
    CustomLdapUserDetailsContextMapper customLdapUserDetailsContextMapper(UserDetailsService userDetailsService)
    {
        CustomLdapUserDetailsContextMapper mapper = new CustomLdapUserDetailsContextMapper();
        mapper.setCustomUserDetailsService(userDetailsService);
        return mapper;
    }
}
配置说明
  • 认证执行顺序完全符合预期:收到登录请求后先尝试LDAP绑定认证,认证成功直接返回结果;如果LDAP查无用户、密码错误导致认证失败,自动回退到JDBC表单认证逻辑。
  • 无需额外定义LdapAuthenticationManagerFactory相关Bean,直接注册Provider的方式更贴合Spring Security 5.7+的组件化设计,和旧版配置的执行逻辑完全一致。
  • 如果项目中自定义了PasswordEncoder,直接注入到DaoAuthenticationProvider即可,没有自定义的话注入Spring Boot自动配置的PasswordEncoder实例就行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 19:06:39