我尝试在SecurityConfig Java Config类中自动装配自定义UserDetailsService实现时获得java.lang.IllegalArgumentException: A UserDetailsService must be set
。以下是我的配置类的概述。
Root config
@Configuration
@Import(value = { SecurityConfig.class, ServiceConfig.class })
public class RootConfig
{
}
ServiceConfig
@Configuration
@ComponentScan(value = "basepackage.service")
// this package includes the custom UserDetailsService implementation
// annotated by @Service
public class ServiceConfig
{
}
SecurityConfig
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends GlobalMethodSecurityConfiguration
{
// this service is injected using setter injection, omitted for clarity
private UserDetailsService userDetailsService;
@Autowired
public void registerGlobal(AuthenticationManagerBuilder auth)
throws Exception
{
auth.userDetailsService(userDetailsService);
}
}
现在,问题是:有时(但有时候 - 似乎完全随机)自定义UserDetailsService在实例化methodSecurityInterceptor
之前没有自动装配,我得到org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'methodSecurityInterceptor' defined in class basepackage.SecurityConfig...
并且堆栈结束于< / p>
Caused by: java.lang.IllegalArgumentException: A UserDetailsService must be set
at org.springframework.util.Assert.notNull(Assert.java:112)
at org.springframework.security.authentication.dao.DaoAuthenticationProvider.doAfterPropertiesSet(DaoAuthenticationProvider.java:94)
正如我之前提到的,UserDetailsService
实现使用@Service
注释进行注释,并且应该按照正确的顺序由ServiceConfig
实例化。只有在部署应用程序时,才会出现此问题。通常一切都正确实例化。当我使用UserDetailsService
注释在SecurityConfig
内创建@Bean
bean时,一切都很好。但我更喜欢将服务bean与SecurityConfig
分开。我尝试了@Order
注释,但没有成功。
为什么会这样?另外,为什么它随机发生而不是每次都发生?为什么Spring无法以正确的顺序实例化bean?我很感激你的帮助。
答案 0 :(得分:1)
我正在处理完全相同的问题。有趣的是它只发生在Java 8中;如果我下载到Java 7,问题就会消失。我开始使用java 8中的一些LocalDate东西,因此不再是一个选项。
无论如何,我没有能够自动装入它并且我确实希望我的服务保持在一起而不是自动装入它,我只是将它提供给AuthenticationManagerBuilder(我在CustomUserDetailsService中添加了一个构造函数) )。然后,您可以将服务保留在服务包中。当然,你不会在那时将它注释为服务,这可能会破坏你的整个目的,因为它有点像春天一样,但我想我还是会发布这个选项。
@Autowired
public void configureGlobal( AuthenticationManagerBuilder auth ) throws Exception
{
auth
.userDetailsService( new CustomUserDetailsService() )
.passwordEncoder( passwordEncoder() );
}
答案 1 :(得分:1)
我正在处理同样的问题
作为一种解决方法,我已注释@Resource
UserDetailsService
(看起来@Resource
依赖关系是在@Autowired
之前注入的)
答案 2 :(得分:1)
是的,这必须是一个错误。在我的自定义身份验证提供程序中使用一些虚拟逻辑覆盖doAfterPropertiesSet()可以防止错误。在覆盖方法中设置breakpoing,显然当UserDetailsService最初为null时,它会立即设置。
@Component
public class CustomAuthenticationDaoProvider extends DaoAuthenticationProvider
...
@Override
protected void doAfterPropertiesSet() throws Exception {
if(super.getUserDetailsService() != null){
System.out.println("UserDetailsService has been configured properly");
}
}
答案 3 :(得分:1)
我在寻找类似问题时偶然发现了这个问题。 如果这对某人有帮助,
对我有用的解决方案:
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authProvider());
}
@Bean
public DaoAuthenticationProvider authProvider() throws Exception {
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(userDetailsService);
authProvider.setPasswordEncoder(encoder());
return authProvider;
}
我必须创建一个DaoAuthenticationProvider(或它的任何自定义子类)并按上面的方式设置注入的userDetailsService。
答案 4 :(得分:0)
这是一种非常奇怪的行为,它刚好发生在我身上。有时候它会起作用,有时它会破坏&#34; Bean of name&#39; UserDetailsService&#39;必须设置为DaoAuthenticationProvider&#34;或那些线上的东西。我通过在配置类的构造函数中添加@Autowired注释来修复它。
@Autowired
public WebSecurityConfig(UserDetailsServiceImpl userDetailsService){
this.userDetailsService = userDetailsService;
}
在setter上应用注释并不起作用,无论如何都是非常奇怪的行为。
答案 5 :(得分:0)
当我在我的类中有一个未使用的属性时,我遇到了这个问题,扩展了WebSecurityConfigurerAdapter
@Autowired
private AuthenticationManager authenticationManager;
删除它解决了我的问题。