无法自动assembly字段:private org.springframework.security.core.userdetails.UserDetailsS​​ervice

我是Spring的新手,所以我一直在寻找安全方面的东西。 每次我运行我的应用程序时,我得到:

org.springframework.beans.factory.BeanCreationException:创建名为’securityConfig’的bean时出错:注入自动连接的依赖项失败; 嵌套exception是org.springframework.beans.factory.BeanCreationException:无法自动assembly字段:private org.springframework.security.core.userdetails.UserDetailsS​​ervice com.entirety.app.config.SecurityConfig.userDetailsS​​erviceImplementation; 嵌套exception是org.springframework.beans.factory.NoSuchBeanDefinitionException:找不到类型为[org.springframework.security.core.userdetails.UserDetailsS​​ervice]的限定bean依赖:预期至少有1个bean符合此依赖关系的autowire候选者。 依赖注释:{@ org.springframework.beans.factory.annotation.Autowired(required = true)}

我用精梳梳理了我的代码,无法查明问题。

Spring Framework版本:3.2.5.RELEASE Spring Security版本:3.2.0.M2

SecurityConfig.java

package com.entirety.app.config; import com.entirety.app.service.implement.UserDetailsServiceImplementation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; 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 javax.sql.DataSource; @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled=true) public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private DataSource dataSource; @Autowired private UserDetailsService userDetailsServiceImplementation; @Override protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception { auth.jdbcAuthentication().dataSource(dataSource); } @Override protected void configure(HttpSecurity http) throws Exception { http.userDetailsService(userDetailsServiceImplementation) .authorizeUrls() .antMatchers("/admin/**").hasRole("ADMIN") .antMatchers("/sec/**").hasRole("MODERATOR") .antMatchers("/*").permitAll() .anyRequest().anonymous().and().exceptionHandling().accessDeniedPage("/denied").and() .formLogin() .loginProcessingUrl("/j_spring_security_check") .loginPage("/login") .failureUrl("/error-login") .and() .logout() .logoutUrl("/j_spring_security_logout") .logoutSuccessUrl("/"); } @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } } 

CrmUserService.java

 @Service("userService") @Transactional public class CrmUserService implements UserDetailsService { @Autowired private UserDAO userDAO; @Override public UserDetails loadUserByUsername(String login) throws UsernameNotFoundException { com.entirety.app.domain.User domainUser = userDAO.getUser(login); boolean enabled = true; boolean accountNonExpired = true; boolean credentialsNonExpired = true; boolean accountNonLocked = true; return new User( domainUser.getLogin(), domainUser.getPassword(), enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, getAuthorities(domainUser.getAuthority().getId()) ); } public Collection getAuthorities(Integer role) { List authList = getGrantedAuthorities(getRoles(role)); return authList; } public List getRoles(Integer role) { List roles = new ArrayList(); if (role.intValue() == 1) { roles.add("ROLE_MODERATOR"); roles.add("ROLE_ADMIN"); } else if (role.intValue() == 2) { roles.add("ROLE_MODERATOR"); } return roles; } public static List getGrantedAuthorities(List roles) { List authorities = new ArrayList(); for (String role : roles) { authorities.add(new SimpleGrantedAuthority(role)); } return authorities; } } 

没有合理的理由说明为什么它应该失败呢。

注意:

我的IDE可以链接autowire(它知道自动assembly的位置和所有内容),但编译失败。

编辑2:我从SecurityConfig.java文件中删除了以下代码

 @Autowired private UserDataService userDataService; 

并将其添加到我知道的POJO和控制器之一,定期调用并包含其他服务。 在这种情况下,将该代码粘贴到我的baseController.java文件中,该文件指向呈现主页。 该服务编译正确,我甚至可以在控制器内调用它。

所以这个问题只与SecurityConfig.java这样的配置文件隔离开来,这是它唯一不起作用的时候。

编辑3:添加了额外的文件

SecurityInitializer.java

 @Order(2) public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer { } 

WebInitializer.java

 @Order(1) public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class[] getRootConfigClasses() { return new Class[] { PersistanceConfig.class, SecurityConfig.class }; //To change body of implemented methods use File | Settings | File Templates. } @Override protected Class[] getServletConfigClasses() { return new Class[] { WebConfig.class }; } @Override protected String[] getServletMappings() { return new String[] {"/"}; } // @Override // protected Filter[] getServletFilters() { // CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter(); // characterEncodingFilter.setEncoding("UTF-8"); // return new Filter[] { characterEncodingFilter}; // } } 

MVC-调度-servlet.xml中

        

web.xml中

  Spring MVC Application  mvc-dispatcher org.springframework.web.servlet.DispatcherServlet 1   mvc-dispatcher /   

更新(提供完整示例后)

看来你有很多问题。

web.xml与AbstractAnnotationConfigDispatcherServletInitializer

您创建的应用程序有一个web.xml,用于配置名为mvc-dispatcher的DispatcherServlet。 mvc-dispatcher有一个mvc-dispatcher-servlet.xml配置,它加载了com.springapp.sectest包中的所有bean。 这意味着mvc-dispatcher可以找到您的UserDetailsService

该应用程序还有一个AbstractAnnotationConfigDispatcherServletInitializer,它创建了一个加载WebConfig java配置的DispatcherServlet 。 此DispatcherServlet无法看到mvc-dispatcher创建的任何Bean。

简而言之,您应该使用web.xml或AbstractAnnotationConfigDispatcherServletInitializer配置DispatcherServlet而不是两者。

getRootConfigClasses vs getServletConfigClasses

getRootConfigClasses中的任何配置通常称为根或父配置,并且无法查看getServletConfigClasses中定义的bean。 Spring Security使用由@EnableWebSecurity批注创建的名为springSecurityFilterChain的filter保护getRootConfigClasses中定义的应用程序。 这意味着通常最好将Spring Security的配置放在getRootConfigClasses中。 这有一些例外,比如你想在Spring MVC控制器上做方法安全性。

getServletConfigClasses中的任何配置通常称为子配置,并且可以查看getRootConfigClasses中定义的bean。 getServletConfigClasses配置DispatcherServlet并且必须包含Spring MVC的bean(即Controllers,ViewResovlers等)。 getRootConfigClasses中定义的任何Spring MVC bean都是可见的但未使用。

此设置虽然有点令人困惑,但允许您使用隔离配置的多个DispatcherServlet实例。 实际上,拥有多个DispatcherServlet实例非常罕见。

根据上面的信息,您应该将UserDetailsService声明及其所有依赖bean移动到getRootConfigClasses。 这将确保SecurityConfig.java可以找到UserDetailsService

拉动修复请求

我已经提交了一个PR来获取你的应用程序,以便它没有错误启动https://github.com/worldcombined/AnnotateFailed/pull/1 。 几点说明

  • 测试不使用父和子上下文,因此它不反映运行应用程序
  • 我不得不移动资源文件夹,以便正确选择
  • 我没有这样做,所以你可以实际validation。 没有login.jsp,你提供的UserDetailsS​​ervice总是返回null而是我试图certificate这里的错误得到了回答。

原始答案

根据这个评论:

@ComponentScan在我的mvc-dispatcher-servlet.xml中作为进行

您似乎正在Dispatcher配置中配置服务,而不是在根上下文中配置服务。

Spring Security的配置通常在根上下文中配置。 例如,可以扩展AbstractSecurityWebApplicationInitializer,如下所示:

 import org.springframework.security.web.context.*; public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer { } 

您是如何导入安全配置的? 如果Spring Security配置位于根上下文中,则它将不会看到Dispatcher Servlet上下文中定义的bean。

解决方案是在根上下文中移动服务配置,或将Spring Security配置移动到调度程序的ApplicationContext。 例如,如果您的调度程序servlet名为mvc,则将Spring Security配置移动到调度程序上下文将如下所示。

 public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer { protected String getDispatcherWebApplicationContextSuffix() { return "mvc"; } } 

将@component用于SecurityConfig类

它应该按类型自动assembly但是……

您将UserDetailService命名为

 @Service("userService") 

尝试将您的字段命名为相同

 @Autowired private UserDetailsService userService; 

如果尝试将此注释添加到SecurityConfig类,该怎么办?

@ComponentScan(basePackages =“包含UserDetailsS​​ervice的包”)