java 自定义 UserDetailsS​​ervice 似乎不是自动装配的

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/35344135/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 00:01:58  来源:igfitidea点击:

Custom UserDetailsService it seems to be not autowired

javaspringspring-mvcspring-security

提问by DevKev

Well I've expended quite a time figuring out what the problem with my code is. According to the trace that tomcat is sending me it has something to do with a custom UserDetailsServicethat I create for connecting Spring Security and JPA to make a login system based on data in a Database. I've read several articles so far talking about this issue but I haven't found a solution for my one. So heres the error trace:

好吧,我花了很长时间才弄清楚我的代码有什么问题。根据 tomcat 发送给我的跟踪,它与UserDetailsService我为连接 Spring Security 和 JPA 以基于数据库中的数据创建登录系统而创建的自定义有关。到目前为止,我已经阅读了几篇讨论这个问题的文章,但我还没有找到适合我的解决方案。所以继承人的错误跟踪:

 ERROR: org.springframework.web.context.ContextLoader - Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'springSecurityConfig': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: org.springframework.security.core.userdetails.UserDetailsService com.trabajotoo.saleisi.configuration.SpringSecurityConfig.userDetailsService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.security.core.userdetails.UserDetailsService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true), @org.springframework.beans.factory.annotation.Qualifier(value=customUserDetailsService)}
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1214)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getObject(AbstractBeanFactory.java:306)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:839)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:538)
    at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:446)
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:328)
    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:107)
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4937)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5434)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549)
    at java.util.concurrent.FutureTask.run(FutureTask.java:262)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:745)
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: org.springframework.security.core.userdetails.UserDetailsService com.trabajotoo.saleisi.configuration.SpringSecurityConfig.userDetailsService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.security.core.userdetails.UserDetailsService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true), @org.springframework.beans.factory.annotation.Qualifier(value=customUserDetailsService)}
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:573)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331)
    ... 22 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.security.core.userdetails.UserDetailsService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true), @org.springframework.beans.factory.annotation.Qualifier(value=customUserDetailsService)}
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1373)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1119)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1014)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:545)
    ... 24 more

Heres my CustomUserDetailsService:

这是我的CustomUserDetailsService

package com.trabajotoo.saleisi.services;


import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;

import com.trabajotoo.saleisi.model.RolAsignado;
import com.trabajotoo.saleisi.model.Usuario;

@Service("customUserDetailsService")
public class CustomUserDetailsService implements UserDetailsService {

    @Autowired
    private UsuarioService userService;

    @Transactional(readOnly = true)
    public UserDetails loadUserByUsername(String userName) throws 
    UsernameNotFoundException {
        Usuario user = userService.findByUsername(userName);
        if (user == null){
            System.out.println("User not found");
            throw new UsernameNotFoundException("Username not found");
        }

        return new User(user.getNomUsuario(), user.getPassword(), user.isEstado(),
                true, true, true, getGrantedAuthorities(user));
    }

    private List<GrantedAuthority> getGrantedAuthorities(Usuario user){
        List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
        for(RolAsignado rolAsign: user.getRolesAsignados()){
            if (rolAsign.isEstado()){
                authorities.add(new SimpleGrantedAuthority("ROLE_"+
            rolAsign.getRol().getCodigo()));
                break;
            }
        }

        return authorities;
    }


}

and here is my SprinSecurityConfigclass:

这是我的SprinSecurityConfig课:

package com.trabajotoo.saleisi.configuration;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

import com.trabajotoo.saleisi.services.CustomSuccessHandler;

@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter{


    @Autowired
    @Qualifier("customUserDetailsService")
    UserDetailsService userDetailsService;

    @Autowired
    CustomSuccessHandler customSuccesHandler;



    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authenticationProvider());
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public DaoAuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
        authenticationProvider.setUserDetailsService(userDetailsService);
        authenticationProvider.setPasswordEncoder(passwordEncoder());
        return authenticationProvider;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception{
        http.authorizeRequests()
        .antMatchers("/register").permitAll()
        .antMatchers("/admin/**").access("hasRole('ADMIN')")
        .antMatchers("/coordinador/**").access("hasRole('COORD')")
        .antMatchers("/director/**").access("hasRole('DIR')")
        .and().formLogin().loginPage("/").permitAll()
        .successHandler(customSuccesHandler).usernameParameter("nomUsuario")
        .passwordParameter("password");
    }

}

Here's my SpringSecurityWebApplicationInitializer:

这是我的SpringSecurityWebApplicationInitializer

package com.trabajotoo.saleisi.configuration;
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;

public class SecurityWebApplicationInitializer extends 
AbstractSecurityWebApplicationInitializer{

}

My WebConfigurationclass:

我的WebConfiguration班级:

package com.trabajotoo.saleisi.configuration;

import javax.annotation.Resource;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.env.Environment;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;

@Configuration
@EnableWebMvc
@Import({HibernateConfig.class})
@ComponentScan({"com.trabajotoo.saleisi.controllers", "com.trabajotoo.saleisi.dao", 
    "com.trabajotoo.saleisi.services"})
public class WebConfiguration extends WebMvcConfigurerAdapter{

    @Resource
    private Environment env;

    // Configuracion de los archivos css,js,etc.
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry){
        registry.addResourceHandler("/resources/**")
        .addResourceLocations("/resources/");
    }

    // Configuracion del manejo de las vistas
    @Bean
    public ViewResolver viewResolver() {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setViewClass(JstlView.class);
        viewResolver.setPrefix("/WEB-INF/views/");
        viewResolver.setSuffix(".jsp");

        return viewResolver;
    }

}

and My WebAppInitializer:

和我的WebAppInitializer

package com.trabajotoo.saleisi.configuration;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

import com.trabajotoo.saleisi.configuration.RootContext;
import com.trabajotoo.saleisi.configuration.WebConfiguration;

public class ApplicationInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[] { RootContext.class, SpringSecurityConfig.class };
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[] { WebConfiguration.class };
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }

}

By the way I'm using Spring Security 4.0.3 and Spring MVC 4.2.4

顺便说一下,我使用的是 Spring Security 4.0.3 和 Spring MVC 4.2.4

回答by Rajesh

Try adding below in WebSecurityConfiguration.java

尝试在 WebSecurityConfiguration.java 中添加以下内容

@Bean
public UserDetailsService userDetailsService() {
    return super.userDetailsService();
}

回答by Ali Dehghani

You're the victim of Application Context Hierarchies. Your CustomUserDetailsServiceis picked up by WebConfigurationcomponent scanning and defined in this context, since:

您是Application Context Hierarchies的受害者。您CustomUserDetailsServiceWebConfiguration组件扫描选中并在此上下文中定义,因为:

@ComponentScan({"com.trabajotoo.saleisi.controllers", "com.trabajotoo.saleisi.dao", 
    "com.trabajotoo.saleisi.services"})
public class WebConfiguration extends WebMvcConfigurerAdapter { ... }

Then you're gonna inject this bean into SpringSecurityConfig, which is WebConfiguration's parent context. Since SpringSecurityConfigcan not access to the beans defined in its child context, it will throw a NoSuchBeanDefinitionException.

然后你要把这个 bean 注入SpringSecurityConfig,它是WebConfiguration的父上下文。由于SpringSecurityConfig无法访问在其子上下文中定义的 bean,它将抛出一个NoSuchBeanDefinitionException.

In order to solve this problem, you should define CustomUserDetailsServicein root context. I'm not quite familiar with your project structure but scanning components in the service layer by RootContextor SpringSecurityConfigmay fix your problem. Something like this:

为了解决这个问题,你应该CustomUserDetailsService在根上下文中定义。我不太熟悉您的项目结构,但扫描服务层中的组件RootContextSpringSecurityConfig可能会解决您的问题。像这样的东西:

@Configuration
@ComponentScan("com.trabajotoo.saleisi.services")
public class RooContext { ... }