每次运行我的应用程序,我得到:
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 org.springframework.security.core.userdetails.UserDetailsService com.entirety.app.config.SecurityConfig.userDetailsServiceImplementation; 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)}
我已经通过一个精细的梳子我的代码,无法确定的问题.
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<? extends GrantedAuthority> getAuthorities(Integer role) { List<GrantedAuthority> authList = getGrantedAuthorities(getRoles(role)); return authList; } public List<String> getRoles(Integer role) { List<String> roles = new ArrayList<String>(); 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<GrantedAuthority> getGrantedAuthorities(List<String> roles) { List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>(); for (String role : roles) { authorities.add(new SimpleGrantedAuthority(role)); } return authorities; } }
没有什么逻辑的理由,为什么它应该是失败,但它是.
注意:
我的IDE可以链接自动连接(这是它知道它的自动连接和所有内容),但编译失败.
编辑2:
我已经从SecurityConfig.java文件中删除了以下代码
@Autowired private UserDataService userDataService;
并将其添加到我知道的POJO和控制器之一,并定期调用并包含其他服务.
在这种情况下,将该代码粘贴到我的baseController.java文件中,该文件指向呈现主页.
该服务正确编译,甚至可以在控制器内调用.
所以这个问题仅仅是配置文件,例如SecurityConfig.java,这是唯一的时候它不起作用.
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中
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="com.entirety.app"/> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/pages/"/> <property name="suffix" value=".jsp"/> </bean> </beans>
web.xml中
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <display-name>Spring MVC Application</display-name> <servlet> <servlet-name>mvc-dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>mvc-dispatcher</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
解决方法
看来你有多个问题.
web.xml与AbstractAnnotationConfigDispatcherServletInitializer
您创建的应用程序具有配置名为mvc-dispatcher的DispatcherServlet的web.xml. mvc-dispatcher具有mvc-dispatcher-servlet.xml的配置,它加载了com.springapp.sectest包中的所有bean.这意味着mvc-dispatcher可以找到您的UserDetailsService.
该应用程序还有一个AbstractAnnotationConfigDispatcherServletInitializer,它创建了一个DispatcherServlet,它加载了WebConfig java配置.此DispatcherServlet无法看到由mvc-dispatcher创建的任何Bean.
简而言之,您应该使用web.xml或AbstractAnnotationConfigDispatcherServletInitializer配置DispatcherServlet,而不是同时配置DispatcherServlet.
getRootConfigClasses与getServletConfigClasses
getRootConfigClasses中的任何配置通常称为根配置或父配置,并且无法查看getServletConfigClasses中定义的bean. Spring Security使用由@EnableWebSecurity注释创建的名为springSecurityFilterChain的Filter来保护您在getRootConfigClasses中定义的应用程序.这意味着通常最好将Spring Security的配置放在getRootConfigClasses中.有一些例外,就像您想要在Spring MVC控制器上执行方法安全性.
getServletConfigClasses中的任何配置通常称为子配置,并且可以查看在getRootConfigClasses中定义的bean. getServletConfigClasses配置DispatcherServlet,并且必须包含Spring MVC(即控制器,ViewResovlers等)的bean.在getRootConfigClasses中定义的任何Spring MVC bean可见但不被使用.
此设置虽然有点混乱,但您可以使用具有隔离配置的多个DispatcherServlet实例.实际上,很少有多个DispatcherServlet实例.
鉴于上述信息,您应将UserDetailsService声明及其所有依赖bean移动到getRootConfigClasses.这将确保SecurityConfig.java可以找到UserDetailsService.
拉请求修复
我已经提交了一个公关,以获得您的应用程序,使其从没有错误https://github.com/worldcombined/AnnotateFailed/pull/1开始.几个笔记
>测试不使用父和子上下文,因此它不反映运行应用程序
>我不得不移动资源文件夹,以便被正确地拾起
>我没有这样做,所以你实际上可以认证.没有login.jsp,你提供的UserDetailsService总是返回null而不是我试图证明这里的错误被回答了.
原始答案
基于此评论:
@ComponentScan is undertaken in my mvc-dispatcher-servlet.xml as
<context:component-scan base-package=”com.entirety.app”/>
看来您正在配置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"; } }