Jan*_*hem 7 java spring spring-security autowired
我有spring boot webapp,它使用基于Java的配置来配置JdbcUserDetailsManager:
@Configuration
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
protected DataSource dataSource;
@Autowired
public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication()
.dataSource(dataSource)
.usersByUsernameQuery("select username as principal, password as credentials, true from users where username = ?")
.authoritiesByUsernameQuery("select username as principal, authority as role from authorities where username = ?")
.rolePrefix("ROLE_");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/api/**")
.authenticated()
.and()
.formLogin()
.successHandler(
(request, response, authentication) -> {
response.setStatus(HttpStatus.NO_CONTENT.value());
})
.failureHandler(
(request, response, authentication) -> {
response.setStatus(HttpStatus.FORBIDDEN.value());
})
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessHandler(
(request, response, authentication) -> {
response.setStatus(HttpStatus.NO_CONTENT.value());
});
}
}
Run Code Online (Sandbox Code Playgroud)
我可以设置一个断点configAuthentication(),所以我知道该方法被调用.我现在想要JdbcUserDetailsManager在我的Application类中注入:
@EnableAutoConfiguration
@ComponentScan
public class Application {
private Environment env;
private UserDetailsManager userDetailsManager;
@Autowired
public Application(JdbcTemplate jdbcTemplate, Environment env, UserDetailsManager userDetailsManager) {
this.env = env;
this.userDetailsManager = userDetailsManager;
...
Run Code Online (Sandbox Code Playgroud)
当我尝试启动我的应用程序时,出现以下错误:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'application': Unsatisfied dependency expressed through constructor argument with index 2 of type [org.springframework.security.provisioning.UserDetailsManager]: : No qualifying bean of type [org.springframework.security.provisioning.UserDetailsManager] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.security.provisioning.UserDetailsManager] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
Run Code Online (Sandbox Code Playgroud)
但我知道在Application调用构造函数之前,JdbcUserDetailsManager正在实例化.这里发生了什么?如何验证JdbcUserDetailsManager实际上是否已在上下文中注册?
更新:通过更改我的SecurityConfig如下,我能够解决问题:
@Configuration
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
protected DataSource dataSource;
private JdbcUserDetailsManager userDetailsManager;
@Autowired
public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception {
this.userDetailsManager = auth.jdbcAuthentication().dataSource(dataSource)
.usersByUsernameQuery(
"select username,password,enabled from users where username=?")
.authoritiesByUsernameQuery(
"select username, role from user_roles where username=?").getUserDetailsService();
}
@Bean(name = "userDetailsManager")
public JdbcUserDetailsManager getUserDetailsManager() {
return userDetailsManager;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/api/**")
.authenticated()
.and()
.formLogin()
.successHandler(
(request, response, authentication) -> {
response.setStatus(HttpStatus.NO_CONTENT.value());
})
.failureHandler(
(request, response, authentication) -> {
response.setStatus(HttpStatus.FORBIDDEN.value());
})
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessHandler(
(request, response, authentication) -> {
response.setStatus(HttpStatus.NO_CONTENT.value());
});
}
}
Run Code Online (Sandbox Code Playgroud)
前往PlínioPantaleão,让我朝着正确的方向前进.不幸的是,我无法将赏金奖励给他们.我还不清楚为什么AuthenticationManagerBuilder不自动在上下文中将UserDetailsService注册为Bean.如果有人可以提供一个权威的答案,说明为什么我必须提供一个吸气剂,或者可以解释如何让它在没有吸气剂的情况下工作(对我来说感觉有些笨拙),我将奖励这个答案的赏金.
Wil*_*ler 12
Spring注入bean,因此你必须在上下文中有一个bean来进行注入.
但是不要在configAuthentication()方法中创建bean .用它自己的方法创建它,然后从configAuthentication()方法中引用它.像这样:
@Bean
public JdbcUserDetailsManager userDetailsManager() {
JdbcUserDetailsManager manager = new JdbcUserDetailsManager();
manager.setDataSource(dataSource);
manager.setUsersByUsernameQuery(
"select username,password,enabled from users where username=?");
manager.setAuthoritiesByUsernameQuery(
"select username, role from user_roles where username=?");
manager.setRolePrefix("ROLE_");
return manager;
}
@Autowired
public void configAuthentication(AuthenticationManagerBuilder builder)
throws Exception {
builder.userDetailsService(userDetailsManager());
}
Run Code Online (Sandbox Code Playgroud)
现在userDetailsManager()生成一个正确配置的bean(允许注入),并且您正在使用它进行身份验证.Spring在这里做了一些魔术,以确保重复调用userDetailsManager()(或任何其他bean定义)一遍又一遍地返回相同的对象,而不是每次都创建新的实例.
我将您的方法名称从更改getUserDetailsManager()为userDetailsManager().这个方法是一个bean定义,而不是一个getter,所以这就是原因.此外,我从@Bean注释中删除了名称,因为Spring在此处自动使用bean名称的方法名称.
填写一些细节的附加说明:
首先,调用jdbcAuthentication()结果是一个新JdbcUserDetailsManager实例,但它完全是内部的(即,不是Spring管理的bean).我们可以说,因为当有多个豆满足一次注射时,Spring会抱怨.有关详细信息,请查看AuthenticationManagerBuilder,JdbcUserDetailsManagerConfigurer和各种超类的源代码.基本上你会看到的是,jdbcAuthentication()调用会产生一个内部详细信息管理器,该调用将userDetailsService()替换该调用.
其次,调用userDetailsService()会丢弃jdbcAuthentication()配置.以下是相关方法AuthenticationManagerBuilder:
public <T extends UserDetailsService>
DaoAuthenticationConfigurer<AuthenticationManagerBuilder,T>
userDetailsService(T userDetailsService) throws Exception {
this.defaultUserDetailsService = userDetailsService;
return apply(
new DaoAuthenticationConfigurer<AuthenticationManagerBuilder,T>
(userDetailsService));
}
Run Code Online (Sandbox Code Playgroud)
这就是为什么我们将JdbcUserDetailsManager配置从jdbcAuthentication()作品中移出并进入userDetailsManager()方法本身.(该jdbcAuthentication()调用基本上暴露了一个方便,流畅的界面来创建JdbcUserDetailsManager,但我们不需要它,因为我们已经有了JdbcUserDetailsManager.)
| 归档时间: |
|
| 查看次数: |
5517 次 |
| 最近记录: |