【问题标题】:Cannot autowire UserDetailsService in GlobalMethodSecurityConfiguration无法在 GlobalMethodSecurityConfiguration 中自动装配 UserDetailsS​​ervice
【发布时间】:2014-08-10 16:03:24
【问题描述】:

尝试在我的 SecurityConfig Java Config 类中自动装配自定义 UserDetailsS​​ervice 实现时,我得到了java.lang.IllegalArgumentException: A UserDetailsService must be set。这是我的配置类的概述。

根配置

@Configuration
@Import(value = { SecurityConfig.class, ServiceConfig.class })
public class RootConfig
{

}

服务配置

@Configuration
@ComponentScan(value = "basepackage.service")
// this package includes the custom UserDetailsService implementation
// annotated by @Service
public class ServiceConfig
{

}

安全配置

@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);
    }
}

现在,问题是:有时(但只是有时 - 它似乎完全随机)自定义 UserDetailsS​​ervice 在 methodSecurityInterceptor 实例化之前不会自动装配,我得到 org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'methodSecurityInterceptor' defined in class basepackage.SecurityConfig... 并且堆栈结束于

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 以正确的顺序实例化。此问题仅在部署应用程序时不时发生。通常一切都正确实例化。当我使用 @Bean 注释在 SecurityConfig 内创建 UserDetailsService bean 时,一切都很好。但我更喜欢将服务 bean 与SecurityConfig 分开。我尝试使用 @Order 注释进行试验,但没有成功。

任何想法为什么会发生这种情况?另外,为什么它是随机发生的,而不是每次都发生?为什么 Spring 不能以正确的顺序实例化 bean?非常感谢您的帮助。

【问题讨论】:

  • @Karthikeyan 你显然没有阅读我的问题......我不会问这么简单的事情。

标签: java spring spring-security autowired spring-java-config


【解决方案1】:

我正在处理完全相同的问题。有趣的是它只发生在 Java 8 中。如果我降到 Java 7,问题就会消失。我开始使用 java 8 中的一些 LocalDate 东西,所以这不再是一个选项。

无论如何,我最终无法自动装配它,我确实希望我的服务保持在一起,所以我没有自动装配它,而是将它提供给 AuthenticationManagerBuilder(我向我的 CustomUserDetailsS​​ervice 添加了一个构造函数)。然后,您可以将您的服务保留在您的服务包中。当然,此时您不会将其注释为服务,这可能会破坏您的全部目的,即它在春季左右工作,但我想我还是会发布该选项。

@Autowired
public void configureGlobal( AuthenticationManagerBuilder auth ) throws Exception
{
    auth
        .userDetailsService( new CustomUserDetailsService() )
        .passwordEncoder( passwordEncoder() );
}

【讨论】:

    【解决方案2】:

    这是一个非常奇怪的行为,前段时间发生在我身上。有时它会正常工作,有时它会因“名称为'UserDetailsS​​ervice'的Bean必须设置为DaoAuthenticationProvider”或这些行上的消息而中断。我通过在我的配置类的构造函数上添加 @Autowired 注释来修复它。

    @Autowired
    public WebSecurityConfig(UserDetailsServiceImpl userDetailsService){
        this.userDetailsService = userDetailsService;
    }
    

    在 setter 上应用注释不起作用,无论如何都是非常奇怪的行为。

    【讨论】:

    • 它对我有用,我处理这个错误将近 1 天,@Autowired 注释在 setter 上不起作用,但在属性中起作用。
    【解决方案3】:

    是的,这一定是一个错误。在我的自定义身份验证提供程序中使用一些虚拟逻辑覆盖 doAfterPropertiesSet() 可以防止错误。在该覆盖方法中设置断点,很明显,虽然 UserDetailsS​​ervice 最初为 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");
            }
        }
    

    【讨论】:

    • 这解决了我java.lang.IllegalArgumentException: A UserDetailsService must be set的情况。
    【解决方案4】:

    我在寻找类似问题时偶然发现了这个问题。 如果这对某人有帮助,

    对我有用的解决方案:

    @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(或它的任何自定义子类)并像上面一样设置注入的 userDetailsS​​ervice。

    【讨论】:

      【解决方案5】:

      我正在处理同样的问题。
      作为一种解决方法,我将@Resource 注释为UserDetailsService(看起来@Resource 依赖项是在@Autowired 之前注入的)

      【讨论】:

        【解决方案6】:

        当我在扩展 WebSecurityConfigurerAdapter 的类中有如下未使用的属性时遇到了这个问题

         @Autowired
        private AuthenticationManager authenticationManager;
        

        删除它解决了我的问题。

        【讨论】:

          猜你喜欢
          • 2016-03-29
          • 2014-08-22
          • 2015-09-14
          • 1970-01-01
          • 1970-01-01
          • 2019-11-04
          • 2015-03-19
          • 1970-01-01
          • 2019-05-19
          相关资源
          最近更新 更多