Spring安全性使用Annotation:NoSuchBeanDefinitionException登录数据库



我正在尝试通过数据库进行spring安全登录。

我的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("uname@gmail.com").password("pass").roles("USER");
    auth.inMemoryAuthentication().withUser("admin@gmail.com").password("pass").roles("ADMIN");
    auth.inMemoryAuthentication().withUser("expert@gmail.com").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;
}

我的主配置代码:

 @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;
}

}

我的消息属性:

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

我还添加了类扩展为AbstractAnnotationConfigDispatcherServlet Initializer。

我的例外:

2015-03-31 13:35:32警告AnnotationConfigWebApplicationContext:487-上下文初始化过程中遇到异常-取消刷新尝试org.springframework.beans.factory.BeanCreationException:创建名为"securityConfig"的bean时出错:自动连接依赖项注入失败;嵌套异常为org.springframework.beans.factory.BeanCreationException:无法自动连接字段:javax.sql.DataSource com.project.pro.config.SecurityConfig.DataSource;嵌套异常为org.springframework.beans.factory.NoSuchBeanDefinitionException:找不到符合[javax.sql.DataSource]类型的依赖项的bean:应至少有1个bean符合此依赖项的自动连线候选项的条件。依赖项注释:{@org.springframework.beans.factory.annotation.Autowired(required=true)}由:org.springframework.beans.factory.BeanCreationException引起:无法自动连接字段:javax.sql.DataSource com.project.pro.config.SecurityConfig.DataSource;嵌套异常为org.springframework.beans.factory.NoSuchBeanDefinitionException:找不到符合[javax.sql.DataSource]类型的依赖项的bean:应至少有1个bean符合此依赖项的自动连线候选项的条件。依赖项注释:{@org.springframework.beans.factory.annotation.Autowired(required=true)}由以下原因引起:org.springframework.beans.factory.NoSuchBeanDefinitionException:找不到[javax.sql.DataSource]类型的符合条件的依赖项bean:应至少有1个符合此依赖项的autowire候选者条件的bean。依赖项注释:{@org.springframework.beans.factory.annotation.Autowired(required=true)}2015-03-31 13:35:32错误ContextLoader:331-上下文初始化失败org.springframework.beans.factory.BeanCreationException:创建名为"securityConfig"的bean时出错:自动连接依赖项注入失败;嵌套异常为org.springframework.beans.factory.BeanCreationException:无法自动连接字段:javax.sql.DataSource com.project.pro.config.SecurityConfig.DataSource;嵌套异常为org.springframework.beans.factory.NoSuchBeanDefinitionException:找不到符合[javax.sql.DataSource]类型的依赖项的bean:应至少有1个bean符合此依赖项的自动连线候选项的条件。依赖项注释:{@org.springframework.beans.factory.annotation.Autowired(required=true)}

这里是我的AbstractAnnotationConfigDispatcherServlet初始化器填充:

公共类ProWebAppInitializer扩展AbstractAnnotationConfigDispatcherServlet Initializer{

@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[] { "/" };
}

}

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

将BasicDataSource移到父ApplicationContext中,它应该可以正常工作。请注意,任何与Spring MVC相关的配置(即EnableWebMvc、Controllers等)都必须在servletConfigClasses中声明,以确保它们被选中。

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

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

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

因此,您可以更新您的配置如下:

@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("uname@gmail.com").password("pass").roles("USER").and()
                .withUser("admin@gmail.com").password("pass").roles("ADMIN").and()
                .withUser("expert@gmail.com").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[] { "/" };
    }
}

最新更新