修改Spring Boot组件扫描包后认证异常问题咨询
看起来你遇到的核心问题是手动声明UserDetailsService Bean打断了Spring Security自动配置的逻辑链,导致默认的DaoAuthenticationProvider没有被正确关联到你的自定义UserService上。下面详细拆解原因和解决方案:
问题根源
Spring Security的自动配置逻辑是这样的:当容器中存在UserDetailsService实例时,它会自动创建DaoAuthenticationProvider并将该实例注入进去,完成认证链路的组装。但当你手动重写userDetailsService()方法并添加@Bean注解时,相当于你接管了UserDetailsService的Bean创建,此时自动配置不会再为你自动生成对应的DaoAuthenticationProvider,最终导致登录时找不到处理UsernamePasswordAuthenticationToken的Provider。
解决方案
方案一:移除手动的UserDetailsService Bean声明(推荐)
既然你的UserService已经通过组件扫描被加载到Spring容器中,完全不需要手动暴露它的Bean。Spring Security的自动配置会自动发现这个UserDetailsService实例,并自动完成DaoAuthenticationProvider的配置。
修改后的WebSecurityConfig代码:
@Configuration @EnableWebSecurity class WebSecurityConfig(@Autowired val userService: UserService) extends WebSecurityConfigurerAdapter with Logging { protected override def configure(http: HttpSecurity): Unit = { http.csrf().disable().authorizeRequests() .antMatchers("/", "/demo").permitAll() .anyRequest().authenticated() .and() .formLogin() .loginProcessingUrl("/login") .permitAll() .and() .logout() .permitAll(); } // 移除这个手动声明的@Bean方法 // @Bean // override def userDetailsService: UserDetailsService = { // userService // } }
方案二:手动配置DaoAuthenticationProvider(如果必须声明Bean)
如果你因为某些场景需要手动暴露UserDetailsService的Bean,那么需要显式创建DaoAuthenticationProvider并将你的UserService注入进去,再配置到认证管理器中:
@Configuration @EnableWebSecurity class WebSecurityConfig(@Autowired val userService: UserService) extends WebSecurityConfigurerAdapter with Logging { protected override def configure(http: HttpSecurity): Unit = { // 保持原有的HTTP安全配置不变 http.csrf().disable().authorizeRequests() .antMatchers("/", "/demo").permitAll() .anyRequest().authenticated() .and() .formLogin() .loginProcessingUrl("/login") .permitAll() .and() .logout() .permitAll(); } @Bean override def userDetailsService: UserDetailsService = { userService } // 手动创建DaoAuthenticationProvider并关联UserDetailsService @Bean def authenticationProvider: AuthenticationProvider = { val provider = new DaoAuthenticationProvider() provider.setUserDetailsService(userDetailsService()) // 如果你的UserService使用了自定义密码编码器,记得在这里配置 // provider.setPasswordEncoder(passwordEncoder()) provider } // 将自定义Provider配置到认证管理器 override protected def configure(auth: AuthenticationManagerBuilder): Unit = { auth.authenticationProvider(authenticationProvider()) } }
对你排查现象的解释
- 注1现象:当只扫描
UserService时,你的WebSecurityConfig没有被加载,Spring Boot会启用默认的SpringBootWebSecurityConfiguration$DefaultConfigurerAdapter,此时自动配置逻辑正常运行,DaoAuthenticationProvider被正确创建并关联到UserService。 - 注2现象:当强制扫描
WebSecurityConfig时,你的手动UserDetailsServiceBean被注册,但没有对应的AuthenticationProvider绑定它——此时UserService只是存在于容器中,但没有被任何认证组件使用,所以登录时会抛出找不到Provider的异常。
内容的提问来源于stack exchange,提问作者Doru Chiulan

