2015-03-31 20 views
0

我正在尝试通过数据库的春季安全登录。春季安全登录数据库使用Annotation:NoSuchBeanDefinitionException

我SecurityConfig代码:

@Configuration 
@EnableWebSecurity 
public class SecurityConfig extends WebSecurityConfigurerAdapter { 

    @Autowired 
    DataSource dataSource; 

    @Autowired 
public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception { 

    auth.jdbcAuthentication().dataSource(dataSource) 
       .passwordEncoder(passwordEncoder()) 
    .usersByUsernameQuery(
         "SELECT email as username,password,active_yn FROM users where email=?") 
    .authoritiesByUsernameQuery(
     "SELECT users.email as username,user_role.role_code as user_role FROM users inner join user_role on users.user_id=user_role.user_id where users.email=?"); 
} 


@Autowired 
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { 
    auth.inMemoryAuthentication().withUser("[email protected]").password("pass").roles("USER"); 
    auth.inMemoryAuthentication().withUser("[email protected]").password("pass").roles("ADMIN"); 
    auth.inMemoryAuthentication().withUser("[email protected]").password("pass").roles("EXPERT"); 
} 

//.csrf() is optional, enabled by default, if using WebSecurityConfigurerAdapter constructor 
@Override 
protected void configure(HttpSecurity http) throws Exception { 

    http.authorizeRequests() 
     .antMatchers("/client/**").access("hasRole('ROLE_USER')") 
     .antMatchers("/admin/**").access("hasRole('ROLE_ADMIN')") 
     .antMatchers("/expert/**").access("hasRole('ROLE_EXPERT')") 
     .and() 
      .formLogin().loginPage("/login").failureUrl("/login?error") 
       .usernameParameter("username").passwordParameter("password") 

     .and() 
      .logout().logoutSuccessUrl("/login?logout") 
     .and() 
      .csrf(); 

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

我MainConfig代码:

@Configuration 
@ComponentScan("com.package.project") 
@EnableWebMvc 
@EnableTransactionManagement 
@PropertySource("classpath:pro-${env.name}.properties") 
@Import({SecurityConfig.class}) 
public class MainConfig extends WebMvcConfigurerAdapter { 
    @Value("${jdbc.classname}") 
    private String jdbcClassname; 
    @Value("${jdbc.url}") 
    private String jdbcUrl; 
    @Value("${jdbc.username}") 
    private String jdbcUsername; 
    @Value("${jdbc.password}") 
    private String jdbcPassword; 
    //code 

@Bean(name = "dataSource") 
public BasicDataSource dataSource() { 
    BasicDataSource dataSource = new BasicDataSource(); 
    dataSource.setDriverClassName(jdbcClassname); 
    dataSource.setUrl(jdbcUrl); 
    dataSource.setUsername(jdbcUsername); 
    dataSource.setPassword(jdbcPassword); 
    return dataSource; 
} 

}

我的Message属性:

jdbc.classname=com.mysql.jdbc.Driver 
jdbc.url=jdbc:mysql://10.0.1.28:3306/test 
jdbc.username=root 
jdbc.password=pass 

我还添加 Ç lass扩展到AbstractAnnotationConfigDispatcherServletInitializer。

我的例外:

 
    2015-03-31 13:35:32 WARN AnnotationConfigWebApplicationContext:487 - Exception encountered during context initialization - cancelling refresh attempt 

    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: javax.sql.DataSource com.project.pro.config.SecurityConfig.dataSource; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [javax.sql.DataSource] 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)} 

    Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: javax.sql.DataSource com.project.pro.config.SecurityConfig.dataSource; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [javax.sql.DataSource] 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)} 

    Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [javax.sql.DataSource] 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)} 

    2015-03-31 13:35:32 ERROR ContextLoader:331 - Context initialization failed 
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: javax.sql.DataSource com.project.pro.config.SecurityConfig.dataSource; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [javax.sql.DataSource] 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)} 

这里我AbstractAnnotationConfigDispatcherServletInitializer豪情:

公共类ProWebAppInitializer扩展AbstractAnnotationConfigDispatcherServletInitializer {

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

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

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

}

+1

你能提供AbstractAnnotationConfigDispatcherServletInitializer – 2015-03-31 16:46:13

+0

@RobWinch:谢谢你的回答,我已经加入AbstractAnnotationConfigDispatcherServletInitializer文件

所以,你可以按如下更新配置。 – 2015-04-01 04:44:06

回答

1

的问题是Spring Security注册在根ApplicationContext中,它无法看到子ApplicationContext中定义的bean(即, servletConfigClasses)。

将BasicDataSource移动到父ApplicationContext,它应该工作得很好。请注意,任何Spring MVC相关配置(即EnableWebMvc,Controllers等)都必须在servletConfigClasses中声明以确保它们被拾取。

因此,在您的实例中,BasicDataSource在MainConfig中定义,它通过getServletConfigClasses公开。这意味着BasicDataSource仅可用于通过getServletConfigClasses公开的配置。

SecurityConfig通过getRootConfigClasses公开,这意味着它无法在getServletConfigClasses中看到任何东西。这意味着它看不到BasicDataSource。

通过getRootConfigClasses公开的任何配置都可以通过getServletConfigClasses查看。

@Configuration 
@EnableWebSecurity 
public class SecurityConfig extends WebSecurityConfigurerAdapter { 

    @Autowired 
    DataSource dataSource; 

    @Autowired 
    public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception { 

     auth 
      .jdbcAuthentication() 
       .dataSource(dataSource) 
       .passwordEncoder(passwordEncoder()) 
       .usersByUsernameQuery(
         "SELECT email as username,password,active_yn FROM users where email=?") 
       .authoritiesByUsernameQuery(
     "SELECT users.email as username,user_role.role_code as user_role FROM users inner join user_role on users.user_id=user_role.user_id where users.email=?") 
       .and() 
      .inMemoryAuthentication() 
       .withUser("[email protected]").password("pass").roles("USER").and() 
       .withUser("[email protected]").password("pass").roles("ADMIN").and() 
       .withUser("[email protected]").password("pass").roles("EXPERT"); 
    } 

    @Override 
    protected void configure(HttpSecurity http) throws Exception { 

     http 
      .authorizeRequests() 
       .antMatchers("/client/**").access("hasRole('ROLE_USER')") 
       .antMatchers("/admin/**").access("hasRole('ROLE_ADMIN')") 
       .antMatchers("/expert/**").access("hasRole('ROLE_EXPERT')") 
       .and() 
      .formLogin() 
       .loginPage("/login"); 
} 

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


@Configuration 
@ComponentScan("com.package.project") 
@EnableTransactionManagement 
@PropertySource("classpath:pro-${env.name}.properties") 
public class MainConfig { 
    @Value("${jdbc.classname}") 
    private String jdbcClassname; 
    @Value("${jdbc.url}") 
    private String jdbcUrl; 
    @Value("${jdbc.username}") 
    private String jdbcUsername; 
    @Value("${jdbc.password}") 
    private String jdbcPassword; 
    //code 

    @Bean(name = "dataSource") 
    public BasicDataSource dataSource() { 
     BasicDataSource dataSource = new BasicDataSource(); 
     dataSource.setDriverClassName(jdbcClassname); 
     dataSource.setUrl(jdbcUrl); 
     dataSource.setUsername(jdbcUsername); 
     dataSource.setPassword(jdbcPassword); 
     return dataSource; 
    } 
} 

@Configuration 
@ComponentScan("com.package.project") 
@EnableWebMvc 
public class WebMvcConfig extends WebMvcConfigurerAdapter { 
    // ... if you don't override any methods you don't need to extend WebMvcConfigurerAdapter 
} 

public class ProWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { 
    @Override 
    protected Class<?>[] getRootConfigClasses() { 
     return new Class[] {SecurityConfig.class, MainConfig.class}; 
    } 

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

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

非常感谢.. 现在我明白了概念 – 2015-04-06 05:09:10

+1

如果回答您的问题,请将我的回复标记为正确 – 2015-04-06 13:58:29