无法将 UserDetailsS​​ervice 自动装配到 WebSecurityConfigurerAdapter

Cannot Autowire UserDetailsService into WebSecurityConfigurerAdapter

您好,我遇到了 Autowired UsrDetailsS​​ervice 的问题,我发现很多其他人也有同样的问题,但没有其他解决方案适合我(我不知道为什么) 我使用java配置(没有xml)

Error code
 org.springframework.beans.factory.BeanCreationException: 
Error creating bean with name 'securityConfig':
Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException:
Could not autowire field: private com.mycompany.delivery.service.AccountServiceImpl com.mycompany.delivery.config.SecurityConfig.accUserDetailsService;
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: 
No qualifying bean of type [com.mycompany.delivery.service.AccountServiceImpl] 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=accUserDetailsService)}

当我将此 class 自动连接到 Controller 或其他任何它工作正常的地方时,其他一切都可以正常自动连接到 WebSecurityConfigurerAdapter 我不能。

我的安全配置:

Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {



    @Autowired
    @Qualifier("accUserDetailsService")
    private AccountServiceImpl accUserDetailsService;

    public AccountServiceImpl getAccUserDetailsService() {
        return accUserDetailsService;
    }

    public void setAccUserDetailsService(AccountServiceImpl accUserDetailsService) {
        this.accUserDetailsService = accUserDetailsService;
    }

   // @Override
    // protected void configure(AuthenticationManagerBuilder registry) throws Exception {
    //     registry.userDetailsService(accUserDetailsService);
    //}
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("mkyong").password("123456").roles("USER");
        auth.inMemoryAuthentication().withUser("admin").password("123456").roles("ADMIN");
        auth.inMemoryAuthentication().withUser("dba").password("123456").roles("DBA");
    }

    //.csrf() is optional, enabled by default, if using WebSecurityConfigurerAdapter constructor
    @Bean(name = "myAuthenticationManager")
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/admin/admin/**").access("hasRole('ROLE_USER')")
                .antMatchers("/admin/partlyVisible/**").access("hasAnyRole('ROLE_USER', 'ROLE_ADMIN')").and()
                .formLogin().loginPage("/admin/login").failureUrl("/admin/login?error")
                .usernameParameter("username").passwordParameter("password")
                .and()
                .logout().logoutSuccessUrl("/admin/login?logout").and()
                .exceptionHandling().accessDeniedPage("/admin/403")
                .and()
                .csrf();
    }
}

我的 WebMvcConfigurerAdapter

@Configuration
@EnableWebMvc
@Import({ SecurityConfig.class })
@ComponentScan(basePackages = "com.mycompany.*")
@ImportResource({"classpath:applicationContext.xml"})
@EnableTransactionManagement
public class MySpringMvcConfig extends WebMvcConfigurerAdapter {

    final static Logger log = LoggerFactory.getLogger(MySpringMvcConfig.class);

    /**
     * Maps the main page to a specific view.
     */
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        log.debug("mapping URL / to home view");
        registry.addViewController("/").setViewName("home");
        registry.addViewController("/snoop").setViewName("snoop");
    }


    /**
     * Enables default Tomcat servlet that serves static files.
     */
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        log.debug("enabling default servlet for static files");
        configurer.enable();
    }

    /**
     * Provides mapping from view names to JSP pages in WEB-INF/jsp directory.
     */
    @Bean
    public ViewResolver viewResolver() {
        log.debug("registering JSP in /WEB-INF/jsp/ as views");
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setViewClass(JstlView.class);
        viewResolver.setPrefix("/WEB-INF/jsp/");
        viewResolver.setSuffix(".jsp");
        return viewResolver;
    }

    /**
     * Provides localized messages.
     */
    @Bean
    public MessageSource messageSource() {
        log.debug("registering ResourceBundle 'Texts' for messages");
        ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
        messageSource.setBasename("Texts");
        return messageSource;
    }

    /**
     * Provides JSR-303 Validator.
     */
    @Bean
    public Validator validator() {
        log.debug("validator()");
        return new LocalValidatorFactoryBean();
    }

}

AbstractAnnotationConfigDispatcherServletInitializer

public class MyStartInitializer extends AbstractAnnotationConfigDispatcherServletInitializer  {

    private Object sc;

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        //create Spring beans context configured in MySpringMvcConfig.class
        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
        ctx.register(MySpringMvcConfig.class);
        ctx.register(SecurityConfig.class);

        //register Spring MVC main Dispatcher servlet
        ServletRegistration.Dynamic disp = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
        disp.setLoadOnStartup(1);
        disp.addMapping("/");



        //register filter setting utf-8 encoding on all requests
        FilterRegistration.Dynamic encoding = servletContext.addFilter("encoding", CharacterEncodingFilter.class);
        encoding.setInitParameter("encoding", "utf-8");
        encoding.addMappingForUrlPatterns(null, false, "/*");

        //register bundle also for JSTL fmt: tags which are not behind DispatcherServlet
        servletContext.setInitParameter(Config.FMT_LOCALIZATION_CONTEXT, "Texts");

    }

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

    @Override
    protected Class<?>[] getServletConfigClasses() {
      return null;
    }

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

AbstractSecurityWebApplicationInitializer

public class SpringSecurityInitializer extends AbstractSecurityWebApplicationInitializer {

   public SpringSecurityInitializer() {
        super(SecurityConfig.class);
    }
}

最后我的 UserDetailsS​​ervice

@Service(value = "accUserDetailsService")
public class AccountServiceImpl implements UserDetailsService {


    @Autowired
    private AccountDAO accountDao;

    public AccountDAO getAccountDao() {
        return accountDao;
    }

    public void setAccountDao(AccountDAO accountDao) {
        this.accountDao = accountDao;
    }

    @Override
    public UserDetails loadUserByUsername(String string) throws UsernameNotFoundException {
        UserDetails userDetails = null;
        Account account = accountDao.getByLogin(string);

        if (account == null) {
            throw new UsernameNotFoundException("Account not found.");
        }

        userDetails = new AccountAdapter(account);
        return userDetails;
    }


}

感谢您的帮助

又过了一个小时,我成功了(但不确定how/why)

我的安全配置:

@Configuration
@EnableWebSecurity

改为

@Configuration
@EnableWebMvcSecurity
@ImportResource({"classpath:applicationContext.xml"})
@EnableGlobalMethodSecurity

ImportResource 很重要,但现在我有两次 importrecource,第一次在这里,第二次在 WebMvcConfigurerAdapter

如果我对这个解释有误,请纠正我。

使用@EnableWebSecurity 后,spring 不允许使用@AutoWired 然后我查看了@@EnableWebSecurity,它没有@Component 或任何Sterotype 注释所以我的结论是这样因为不允许@Autowired.

@ImportResource({"classpath:applicationContext.xml"}) 意味着你对 spring 说我需要 applicationContext 在这个 class 它基本上包含所有 bean,这就是为什么它之后没有抛出任何错误的原因。