Spring 安全登录数据库使用注解:NoSuchBeanDefinitionException
Spring security Login database using Annotation :NoSuchBeanDefinitionException
我正在尝试 spring 通过数据库安全登录。
我的安全配置代码:
@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
我也添加了
class 扩展到 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 Fille:
public class 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[] { "/" };
}
}
问题是 Spring 安全性在根 ApplicationContext 中注册,它看不到子 ApplicationContext 中定义的 bean(即 servletConfigClasses)。
将 BasicDataSource 移至父 ApplicationContext,它应该可以正常工作。请注意,必须在 servletConfigClasses 中声明任何 Spring MVC 相关配置(即 EnableWebMvc、Controllers 等)以确保它们被拾取。
所以在您的实例中,BasicDataSource 是在通过 getServletConfigClasses 公开的 MainConfig 中定义的。这意味着 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("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[] { "/" };
}
}
我正在尝试 spring 通过数据库安全登录。
我的安全配置代码:
@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
我也添加了 class 扩展到 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 Fille:
public class 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[] { "/" };
}
}
问题是 Spring 安全性在根 ApplicationContext 中注册,它看不到子 ApplicationContext 中定义的 bean(即 servletConfigClasses)。
将 BasicDataSource 移至父 ApplicationContext,它应该可以正常工作。请注意,必须在 servletConfigClasses 中声明任何 Spring MVC 相关配置(即 EnableWebMvc、Controllers 等)以确保它们被拾取。
所以在您的实例中,BasicDataSource 是在通过 getServletConfigClasses 公开的 MainConfig 中定义的。这意味着 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("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[] { "/" };
}
}