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

升级Spring Security 5.7.3遇UserDetailsService Bean缺失问题求助

问题排查:Spring Security 5.7.3升级后找不到UserDetailsService Bean

异常信息

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.security.core.userdetails.UserDetailsService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at app//org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1799)
    ...

相关代码

WebSecurityConfigAD配置类

@Slf4j
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@ComponentScan
public class WebSecurityConfigAD implements WebMvcConfigurer
{
    @Autowired
    private ApplicationContext applicationContext;
    @Autowired
    private UserRepository repo;
    @Value( "${ad.domain}" )
    private String AD_DOMAIN;
    @Value( "${ad.url}" )
    private String AD_URL;
    @Value( "${ad.searchfilter}")
    private String SEARCH_FILTER;
    @Autowired
    private ConfigPDF configPdf;
    @Autowired(required=true)
    private MyUserDetailService userDetailsService;

    @Bean
    public SecurityFilterChain filterChain( HttpSecurity http ) throws Exception
    {
        AuthenticationManagerBuilder authManagerBuilder = http.getSharedObject(AuthenticationManagerBuilder.class);
        http.authorizeRequests().antMatchers( "/resources/**" ).permitAll().antMatchers( "/css/**" ).permitAll().antMatchers( "/img/**" ).permitAll().antMatchers( "/images/**" ).permitAll().anyRequest().authenticated().and().formLogin().loginPage( "/login.html" ).loginProcessingUrl( "/login" )
                .permitAll().successHandler( formLoginSuccessHandler() );
        http.logout().logoutRequestMatcher( new AntPathRequestMatcher( "/logout", "GET" ) ).logoutSuccessUrl( "/" ).deleteCookies( "JSESSIONID", "user", "login" ).invalidateHttpSession( true ).clearAuthentication( true );
        http.headers().frameOptions().sameOrigin();
        http.rememberMe().key( "uniqueAndSecret" );
        http.sessionManagement().invalidSessionUrl( "/login.html" );
        http.csrf().disable();
        http.authenticationManager( authenticationManager(authManagerBuilder));
        return http.build();
    }

    @Bean
    public AuthenticationManager authenticationManager( AuthenticationManagerBuilder authManagerBuilder  ) throws Exception
    {
        log.info( "DO some Authentication Manger things" );
       return (AuthenticationManager)authManagerBuilder.authenticationProvider(activeDirectoryLdapAuthenticationProvider()).userDetailsService( userDetailsService).and.build();
    }

    @Bean
    public AuthenticationProvider activeDirectoryLdapAuthenticationProvider()
    {
        log.info( "Authenticate: "+AD_DOMAIN+", "+AD_URL );
        ActiveDirectoryLdapAuthenticationProvider provider = new ActiveDirectoryLdapAuthenticationProvider( AD_DOMAIN, AD_URL );
        provider.setConvertSubErrorCodesToExceptions( true );
        provider.setUseAuthenticationRequestCredentials( true );
        provider.setSearchFilter( SEARCH_FILTER );
        return provider;
    }
}

MyUserDetailService类

@Service
@Transactional
public class MyUserDetailService implements UserDetailsService
{
    @Override
    public UserDetails loadUserByUsername( String username ) throws UsernameNotFoundException
    {
        return null;
    }
}

可能原因分析

  1. ComponentScan扫描范围不匹配:WebSecurityConfigAD上的@ComponentScan未指定扫描包,默认仅扫描当前类所在包及其子包。如果MyUserDetailService位于其他未被扫描的包下,Spring无法将其识别为Bean。此外,若项目主启动类使用@SpringBootApplication(自带@ComponentScan),WebSecurityConfigAD上的@ComponentScan会覆盖默认扫描规则,导致主启动类的扫描范围失效。

  2. Bean初始化顺序问题:在filterChain方法中直接调用authenticationManager(authManagerBuilder)创建AuthenticationManager,此时MyUserDetailService可能尚未完成初始化,导致Autowired注入失败。

  3. 冗余配置冲突:ActiveDirectoryLdapAuthenticationProvider本身已内置用户认证逻辑,若无需自定义UserDetailsService的额外处理,强行配置反而可能引发依赖问题,但此点不影响Bean的识别。

解决方案

方案1:修正ComponentScan扫描范围

  • 移除冗余的@ComponentScan:如果项目主启动类已使用@SpringBootApplication,直接删除WebSecurityConfigAD上的@ComponentScan注解,让Spring默认扫描主启动类所在包及子包。
  • 明确指定扫描包:若必须保留@ComponentScan,需明确包含MyUserDetailService所在的包,例如:
@ComponentScan(basePackages = {"com.yourproject.service", "com.yourproject.config"})

方案2:调整AuthenticationManager配置逻辑

避免手动在filterChain中触发AuthenticationManager创建,交由Spring自动管理Bean生命周期:

  1. 修改filterChain方法,删除http.authenticationManager(authenticationManager(authManagerBuilder));这一行。
  2. 调整authenticationManager方法,改为注入AuthenticationManagerBuilder而非传入参数:
@Bean
public AuthenticationManager authenticationManager(AuthenticationManagerBuilder auth) throws Exception {
    log.info("DO some Authentication Manger things");
    auth.authenticationProvider(activeDirectoryLdapAuthenticationProvider())
        .userDetailsService(userDetailsService);
    return auth.build();
}

Spring会自动将该AuthenticationManager注入到SecurityFilterChain中,避免初始化顺序问题。

方案3:检查自定义UserDetailsService的有效性

虽然当前问题是Bean未被识别,但后续需修正loadUserByUsername方法的返回值(当前返回null会导致认证失败),例如从数据库加载用户权限信息:

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    // 示例:从数据库查询用户
    User user = repo.findByUsername(username);
    if (user == null) {
        throw new UsernameNotFoundException("User not found: " + username);
    }
    // 构建UserDetails对象
    return User.withUsername(user.getUsername())
               .password(user.getPassword()) // AD认证后可忽略密码,此处仅为示例
               .authorities(user.getRoles().stream().map(Role::getName).toArray(String[]::new))
               .build();
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 19:45:40