Spring 安全自定义过滤器(在 AuthenticationManager bean 已经存在时创建它的原因)
Spring security custom filter (reason for creating AuthenticationManager bean while it already exists)
当我们使用自定义过滤器时,我们需要注入类型为 AuthenticationManager
的 bean。
据我所知,如果我们使用默认过滤器,那么 Spring 会自动提供身份验证管理器。这使我得出结论,Spring 上下文中已经有一个 AuthenticationManager
bean(根据我的理解)。
但问题是我的假设是不正确的。我必须创建一个 AuthenticationManager
的 bean 并将其注入过滤器。
我的假设有什么问题?为什么我们需要在 Bean 已经存在的情况下创建它?
Spring 使用 AuthenticationManager
找到合适的身份验证提供程序,但默认情况下没有将 AuthenticationManager
注册为 bean。查看 HttpSecurityConfiguration
class.
的源代码
@Bean(HTTPSECURITY_BEAN_NAME)
@Scope("prototype")
HttpSecurity httpSecurity() throws Exception {
WebSecurityConfigurerAdapter.LazyPasswordEncoder passwordEncoder = new WebSecurityConfigurerAdapter.LazyPasswordEncoder(
this.context);
AuthenticationManagerBuilder authenticationBuilder = new WebSecurityConfigurerAdapter.DefaultPasswordEncoderAuthenticationManagerBuilder(
this.objectPostProcessor, passwordEncoder);
authenticationBuilder.parentAuthenticationManager(authenticationManager());
HttpSecurity http = new HttpSecurity(this.objectPostProcessor, authenticationBuilder, createSharedObjects());
// @formatter:off
http
.csrf(withDefaults())
.addFilter(new WebAsyncManagerIntegrationFilter())
.exceptionHandling(withDefaults())
.headers(withDefaults())
.sessionManagement(withDefaults())
.securityContext(withDefaults())
.requestCache(withDefaults())
.anonymous(withDefaults())
.servletApi(withDefaults())
.apply(new DefaultLoginPageConfigurer<>());
http.logout(withDefaults());
// @formatter:on
return http;
}
private AuthenticationManager authenticationManager() throws Exception {
return (this.authenticationManager != null) ? this.authenticationManager
: this.authenticationConfiguration.getAuthenticationManager();
}
如您所见,它在 HttpSecurity
中注册了一个身份验证管理器生成器。稍后在 HttpSecurity
class 中,它将使用此构建器构建身份验证管理器并将其注册到共享对象中 [参见 HttpSecurity
中的方法 beforeConfigure()
。
@Override
protected void beforeConfigure() throws Exception {
setSharedObject(AuthenticationManager.class, getAuthenticationRegistry().build());
}
并且每当它需要身份验证管理器时使用 HttpSecurity
来获取它,如下所示:
AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManager.class);
当我们使用自定义过滤器时,我们需要注入类型为 AuthenticationManager
的 bean。
据我所知,如果我们使用默认过滤器,那么 Spring 会自动提供身份验证管理器。这使我得出结论,Spring 上下文中已经有一个 AuthenticationManager
bean(根据我的理解)。
但问题是我的假设是不正确的。我必须创建一个 AuthenticationManager
的 bean 并将其注入过滤器。
我的假设有什么问题?为什么我们需要在 Bean 已经存在的情况下创建它?
Spring 使用 AuthenticationManager
找到合适的身份验证提供程序,但默认情况下没有将 AuthenticationManager
注册为 bean。查看 HttpSecurityConfiguration
class.
@Bean(HTTPSECURITY_BEAN_NAME)
@Scope("prototype")
HttpSecurity httpSecurity() throws Exception {
WebSecurityConfigurerAdapter.LazyPasswordEncoder passwordEncoder = new WebSecurityConfigurerAdapter.LazyPasswordEncoder(
this.context);
AuthenticationManagerBuilder authenticationBuilder = new WebSecurityConfigurerAdapter.DefaultPasswordEncoderAuthenticationManagerBuilder(
this.objectPostProcessor, passwordEncoder);
authenticationBuilder.parentAuthenticationManager(authenticationManager());
HttpSecurity http = new HttpSecurity(this.objectPostProcessor, authenticationBuilder, createSharedObjects());
// @formatter:off
http
.csrf(withDefaults())
.addFilter(new WebAsyncManagerIntegrationFilter())
.exceptionHandling(withDefaults())
.headers(withDefaults())
.sessionManagement(withDefaults())
.securityContext(withDefaults())
.requestCache(withDefaults())
.anonymous(withDefaults())
.servletApi(withDefaults())
.apply(new DefaultLoginPageConfigurer<>());
http.logout(withDefaults());
// @formatter:on
return http;
}
private AuthenticationManager authenticationManager() throws Exception {
return (this.authenticationManager != null) ? this.authenticationManager
: this.authenticationConfiguration.getAuthenticationManager();
}
如您所见,它在 HttpSecurity
中注册了一个身份验证管理器生成器。稍后在 HttpSecurity
class 中,它将使用此构建器构建身份验证管理器并将其注册到共享对象中 [参见 HttpSecurity
中的方法 beforeConfigure()
。
@Override
protected void beforeConfigure() throws Exception {
setSharedObject(AuthenticationManager.class, getAuthenticationRegistry().build());
}
并且每当它需要身份验证管理器时使用 HttpSecurity
来获取它,如下所示:
AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManager.class);