- 1、从Spring容器中获取WebSecurityConfigurerAdapter实例
- 2、创建WebSecurity并且赋予配置类
- 3、使用WebSecurity构建FilterChainProxy
- 4、WebSecurity构建FilterChainProxy过程
- 4.1、init方法
- 4.1.1、调用getHttp创建HttpSecurity对象
- 4.1.1.1、创建全局AuthenticationManager作为AuthenticationBuilder的父AuthenticationManager
- 4.1.1.2、新建HttpSecurity对象
- 4.1.1.3、添加默认的配置类
- 4.1.1.4、执行configure(http)方法,进一步配置HttpSecurity对象
- 4.1.2、将HttpSecurity对象添加到securityFilterChainBuilders中
- 4.1.1、调用getHttp创建HttpSecurity对象
- 4.2、configure方法
- 4.3、PerformBuild方法
- 4.1、init方法
1、从Spring容器中获取WebSecurityConfigurerAdapter实例
public List<SecurityConfigurer<Filter, WebSecurity>> getWebSecurityConfigurers() {
List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers = new ArrayList<>();
Map<String, WebSecurityConfigurer> beansOfType = beanFactory
.getBeansOfType(WebSecurityConfigurer.class);
for (Entry<String, WebSecurityConfigurer> entry : beansOfType.entrySet()) {
webSecurityConfigurers.add(entry.getValue());
}
return webSecurityConfigurers;
}
Spring
容器中获取WebSecurityConfigurer
的实例,即WebSecurityConfigurerAdapter
。一般实际项目中我们都会去继承该类,虽然平时我们只写了一个SecurityConfig
类去继承,但是允许自定义多个SecurityConfig
继承自WebSecurityConfigurerAdapter
,那么获取到的WebSecurityConfigurerAdapter
实例也将有多个,即将来构建成功后会有多条过滤器链。
2、创建WebSecurity并且赋予配置类
@Autowired(required = false)
public void setFilterChainProxySecurityConfigurer(
ObjectPostProcessor<Object> objectPostProcessor,
@Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers)
throws Exception {
webSecurity = objectPostProcessor
.postProcess(new WebSecurity(objectPostProcessor));
if (debugEnabled != null) {
webSecurity.debug(debugEnabled);
}
webSecurityConfigurers.sort(AnnotationAwareOrderComparator.INSTANCE);
Integer previousOrder = null;
Object previousConfig = null;
for (SecurityConfigurer<Filter, WebSecurity> config : webSecurityConfigurers) {
Integer order = AnnotationAwareOrderComparator.lookupOrder(config);
if (previousOrder != null && previousOrder.equals(order)) {
throw new IllegalStateException(
"@Order on WebSecurityConfigurers must be unique. Order of "
+ order + " was already used on " + previousConfig + ", so it cannot be used on "
+ config + " too.");
}
previousOrder = order;
previousConfig = config;
}
for (SecurityConfigurer<Filter, WebSecurity> webSecurityConfigurer : webSecurityConfigurers) {
webSecurity.apply(webSecurityConfigurer);
}
this.webSecurityConfigurers = webSecurityConfigurers;
}
new
一个WebSecurity
对象,然后注入到Spring
容器中。对上面获取到的WebSecurityConfigurerAdapter
实例按照优先级进行排序,如果优先级相同,则会抛出异常,然后将上面排好序的WebSecurityConfigurerAdapter
实例存入到WebSecurity
对象中的configurers
属性中。
3、使用WebSecurity构建FilterChainProxy
@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
public Filter springSecurityFilterChain() throws Exception {
boolean hasConfigurers = webSecurityConfigurers != null
&& !webSecurityConfigurers.isEmpty();
if (!hasConfigurers) {
WebSecurityConfigurerAdapter adapter = objectObjectPostProcessor
.postProcess(new WebSecurityConfigurerAdapter() {
});
webSecurity.apply(adapter);
}
return webSecurity.build();
}
在上面创建完成WebSecurity
对象之后,就开始执行WebSecurity
的build
方法创建FilterChainProxy
。
4、WebSecurity构建FilterChainProxy过程
从Spring Security过滤器架构(源码篇)一文中可以知道FilterChainProxy
管理着多个过滤器链,那么,这些过滤器链是怎么构建出来的呢?带着疑问继续打断点执行下去。
上面已经执行到了WebSecurity
对象的build
方法,最后会来到其父类AbstractConfiguredSecurityBuilder
中的doBuild
方法:
@Override
protected final O doBuild() throws Exception {
synchronized (this.configurers) {
this.buildState = BuildState.INITIALIZING;
beforeInit();
init();
this.buildState = BuildState.CONFIGURING;
beforeConfigure();
configure();
this.buildState = BuildState.BUILDING;
O result = performBuild();
this.buildState = BuildState.BUILT;
return result;
}
}
从深入理解WebSecurityConfigurerAdapter(源码篇)一文中可以知道详细的方法就三个,init
,configure
和performBuild
方法。
4.1、init方法
private void init() throws Exception {
Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();
for (SecurityConfigurer<O, B> configurer : configurers) {
configurer.init((B) this);
}
for (SecurityConfigurer<O, B> configurer : this.configurersAddedInInitializing) {
configurer.init((B) this);
}
}
第二步的时候已经将WebSecurityConfigurerAdapter
实例集合,即我们自定义的SecurityConfig
集合放到了WebSecurity
的configurers
属性中,在此处就好用上了。依次执行每个configurer
的init
方法,init
方法干了啥呢?
@Override
public void init(WebSecurity web) throws Exception {
HttpSecurity http = getHttp();
web.addSecurityFilterChainBuilder(http).postBuildAction(() -> {
FilterSecurityInterceptor securityInterceptor = http.getSharedObject(FilterSecurityInterceptor.class);
web.securityInterceptor(securityInterceptor);
});
}
4.1.1、调用getHttp创建HttpSecurity对象
让我们目光移到getHttp
方法上:
protected final HttpSecurity getHttp() throws Exception {
if (this.http != null) {
return this.http;
}
AuthenticationEventPublisher eventPublisher = getAuthenticationEventPublisher();
this.localConfigureAuthenticationBldr.authenticationEventPublisher(eventPublisher);
AuthenticationManager authenticationManager = authenticationManager();
this.authenticationBuilder.parentAuthenticationManager(authenticationManager);
Map<Class<?>, Object> sharedObjects = createSharedObjects();
this.http = new HttpSecurity(this.objectPostProcessor, this.authenticationBuilder, sharedObjects);
if (!this.disableDefaults) {
applyDefaultConfiguration(this.http);
ClassLoader classLoader = this.context.getClassLoader();
List<AbstractHttpConfigurer> defaultHttpConfigurers = SpringFactoriesLoader
.loadFactories(AbstractHttpConfigurer.class, classLoader);
for (AbstractHttpConfigurer configurer : defaultHttpConfigurers) {
this.http.apply(configurer);
}
}
configure(this.http);
return this.http;
}
4.1.1.1、创建全局AuthenticationManager作为AuthenticationBuilder的父AuthenticationManager
在getHttp
方法中调用authenticationManager
方法,在深入理解AuthenticationManagerBuilder(源码篇)一文中已经介绍过,该方法是用来创建全局AuthenticationManager
。
protected AuthenticationManager authenticationManager() throws Exception {
if (!this.authenticationManagerInitialized) {
configure(this.localConfigureAuthenticationBldr);
if (this.disableLocalConfigureAuthenticationBldr) {
this.authenticationManager = this.authenticationConfiguration.getAuthenticationManager();
}
else {
this.authenticationManager = this.localConfigureAuthenticationBldr.build();
}
this.authenticationManagerInitialized = true;
}
return this.authenticationManager;
}
在此方法中,先调用configure
方法:
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
this.disableLocalConfigureAuthenticationBldr = true;
}
有没有觉得这个方法很熟悉,该方法就是我们在自定义配置类SecurityConfig
继承自WebSeucrityConfigAdapter
时会经常会重写的方法,如:
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(sysUserService).passwordEncoder(passwordEncoder());
}
使用auth.userDetailsService(sysUserService)
配置时,AuthenticationManagerBuilder
会创建一个DaoAuthenticationConfigurer
,添加到AuthenticationManagerBuilder
的configurers
属性中,在后面AuthenticationManagerBuilder
构建时会用到。
当我们重写WebSeucrityConfigAdapter#configure
之后,上面的disableLocalConfigureAuthenticationBldr
属性为false,就会使用我们配置的AuthenticationManagerBuilder
来构建AuthenticationManager
对象;当我们没有重写WebSeucrityConfigAdapter#configure
时,disableLocalConfigureAuthenticationBldr
属性变成true,然后就会使用自动注入的authenticationConfiguration
中的getAuthenticationManager
方法构建AuthenticationManager
对象。
4.1.1.1.1、使用自己配置的AuthenticationManagerBuilder构建AuthenticationManager对象
最后会来到其父类AbstractConfiguredSecurityBuilder
中的doBuild
方法,然后又会依次执行init
,configure
和performBuild
方法。从上面可以知道只有一个DaoAuthenticationConfigurer
配置类被添加到AuthenticationManagerBuilder
的configurers
属性中,所以init
与configure
就变成了DaoAuthenticationConfigurer
去执行init
和configure
方法。
4.1.1.1.1.1、DaoAuthenticationConfigurer执行init方法
4.1.1.1.1.2、DaoAuthenticationConfigurer执行configure方法
@Override
public void configure(B builder) throws Exception {
this.provider = postProcess(this.provider);
builder.authenticationProvider(this.provider);
}
在其父类AbstractDaoAuthenticationConfigurer
中被实现,将当前配置好的DaoAuthenticationProvider
对象添加到AuthenticationManagerBuilder
的authenticationProviders
属性中。
4.1.1.1.1.3、AuthenticationManagerBuilder执行performBuild方法
@Override
protected ProviderManager performBuild() throws Exception {
if (!isConfigured()) {
this.logger.debug("No authenticationProviders and no parentAuthenticationManager defined. Returning null.");
return null;
}
ProviderManager providerManager = new ProviderManager(this.authenticationProviders,
this.parentAuthenticationManager);
if (this.eraseCredentials != null) {
providerManager.setEraseCredentialsAfterAuthentication(this.eraseCredentials);
}
if (this.eventPublisher != null) {
providerManager.setAuthenticationEventPublisher(this.eventPublisher);
}
providerManager = postProcess(providerManager);
return providerManager;
}
new
一个ProviderManager
对象,传入authenticationProviders
属性和parentAuthenticationManager
属性。根据上面知道第一个参数其中存入了一个DaoAuthenticationProvider
对象;因为当前是创建全局AuthenticationManager
对象,所以并没有给该parentAuthenticationManager
属性赋值。最后使用postProcess
将new
出来的ProviderManager
对象放入Spring
容器中,并且返回。
4.1.1.1.2、使用AuthenticationConfiguration中的getAuthenticationManager方法构建AuthenticationManager对象
public AuthenticationManager getAuthenticationManager() throws Exception {
if (this.authenticationManagerInitialized) {
return this.authenticationManager;
}
AuthenticationManagerBuilder authBuilder = this.applicationContext.getBean(AuthenticationManagerBuilder.class);
if (this.buildingAuthenticationManager.getAndSet(true)) {
return new AuthenticationManagerDelegator(authBuilder);
}
for (GlobalAuthenticationConfigurerAdapter config : this.globalAuthConfigurers) {
authBuilder.apply(config);
}
this.authenticationManager = authBuilder.build();
if (this.authenticationManager == null) {
this.authenticationManager = getAuthenticationManagerBean();
}
this.authenticationManagerInitialized = true;
return this.authenticationManager;
}
其中的构建过程和上面使用自己配置的AuthenticationManagerBuilder构建AuthenticationManager对象差不多,也是执行init
,configure
和performBuild
方法构建出一个AuthenticationManager
对象并返回。
4.1.1.2、新建HttpSecurity对象
将上面构建好的全局AuthenticationManager
对象放入局部authenticationBuilder
的parent
属性中,然后在new``HttpSecurity
对象的时候将局部authenticationBuilder
当作参数传入进去,将其放到共享对象中,可以通过getAuthenticationRegistry
方法获取出来。
public HttpSecurity(ObjectPostProcessor<Object> objectPostProcessor,
AuthenticationManagerBuilder authenticationBuilder, Map<Class<?>, Object> sharedObjects) {
super(objectPostProcessor);
Assert.notNull(authenticationBuilder, "authenticationBuilder cannot be null");
setSharedObject(AuthenticationManagerBuilder.class, authenticationBuilder);
for (Map.Entry<Class<?>, Object> entry : sharedObjects.entrySet()) {
setSharedObject((Class<Object>) entry.getKey(), entry.getValue());
}
ApplicationContext context = (ApplicationContext) sharedObjects.get(ApplicationContext.class);
this.requestMatcherConfigurer = new RequestMatcherConfigurer(context);
}
4.1.1.3、添加默认的配置类
private void applyDefaultConfiguration(HttpSecurity http) throws Exception {
http.csrf();
http.addFilter(new WebAsyncManagerIntegrationFilter());
http.exceptionHandling();
http.headers();
http.sessionManagement();
http.securityContext();
http.requestCache();
http.anonymous();
http.servletApi();
http.apply(new DefaultLoginPageConfigurer<>());
http.logout();
}
然后执行applyDefaultConfiguration
方法,给上面new
出来的HttpSecurity
对象添加一系列默认的配置类而且还直接添加了一个WebAsyncManagerIntegrationFilter
过滤器。默认的配置类有CsrfConfigurer``ExceptionHandlingConfigurer``HeadersConfigurer``SessionManagementConfigurer``SecurityContextConfigurer``RequestCacheConfigurer``AnonymousConfigurer``ServletApiConfigurer``DefaultLoginPageConfigurer
和LogoutConfigurer
10个配置类。
4.1.1.4、执行configure(http)方法,进一步配置HttpSecurity对象
调用configure(http)
方法,该方法是不是也很熟悉,我们一般在系统项目中的自定义配置类(继承自WebSecurityConfiguerAdapter
)中,也会重写该方法。
protected void configure(HttpSecurity http) throws Exception {
this.logger.debug("Using default configure(HttpSecurity). "
+ "If subclassed this will potentially override subclass configure(HttpSecurity).");
http.authorizeRequests((requests) -> requests.anyRequest().authenticated());
http.formLogin();
http.httpBasic();
}
默认的方法只是添加了FormLoginConfigurer``HttpBasicConfigurer
和ExpressionUrlAuthorizationConfigurer
三个配置类,并且指明了任何请求都必须认证。
如果重写该方法的话,则会按照我们项目需要添加或删除某些配置类,如:
@Override
protected void configure(HttpSecurity http) throws Exception {
http
// 开启跨域访问
.cors()
.and()
// 开启模拟请求,比如API POST测试工具的测试,不开启时,API POST为报403错误
.csrf()
.disable()
// 全局不创建session
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.formLogin()
// 表单登录成功与失败处理器
.failureHandler(authenticationFailureHandler)
.successHandler(authenticationSuccessHandler)
// 退出登录成功处理器
.and()
.logout()
// 退出登录成功处理器
.logoutSuccessHandler(logoutSuccessHandler)
.and()
.authorizeRequests()
// 除了白名单之外的url都需要认证
.antMatchers(SecurityConfigConstant.LOGIN_WHITE_URL)
.permitAll()
.anyRequest()
.authenticated()
// 异常处理器
.and()
.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint)
.accessDeniedHandler(accessDeniedHandler)
.and()
// 禁用页面缓存,返回的都是json
.headers()
.frameOptions()
.disable()
.cacheControl();
}
在上面重写的方法中,我们将csrf
配置类给删除了,以及重新给部分其他原有的配置类进行了自定义配置,以后这里还可以根据项目需要添加额外的手机验证码登录或者第三方登录的配置类,全看自己需要,从这里就可以看出Spring Security的灵活以及强大之处。
最后,将配置好的HttpSecurity
对象返回。
4.1.2、将HttpSecurity对象添加到securityFilterChainBuilders中
public WebSecurity addSecurityFilterChainBuilder(
SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder) {
this.securityFilterChainBuilders.add(securityFilterChainBuilder);
return this;
}
好了,至此WebSecurity
对象的init
方法执行完毕。
🎨总结一下:执行WebSecurity
中的init
方法,实际上是WebSecurity
中的配置类集合Configurers
循环执行每个Configurer
的init
方法,configurers
集合中的数据来源于我们自定义了几个配置类继承自WebSecurityConfigurerAdapter
,其中一个configurer
执行完init
方法之后就会将配置好的HttpSecurity
对象添加到WebSecurity
中的securityFilterChainBuilders
集合中,在接下来的performBuild
方法中会用到这个securityFilterChainBuilders
集合,一个HttpSecurity
构建出一条过滤器链。
4.2、configure方法
private void configure() throws Exception {
Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();
for (SecurityConfigurer<O, B> configurer : configurers) {
configurer.configure((B) this);
}
}
WebSecurityConfigurerAdapter
实例(即我们自定义的配置类-继承自WebSecurityConfigurerAdapter
)集合中的每个Configurer
依次执行configure
方法。
好,我们来看看configure
方法干了啥?
@Override
public void configure(WebSecurity web) throws Exception {
}
别看是个空方法,但是不是很熟悉,在我们需要给某些前端页面的静态资源放行的时候,经常会在自定义配置类中重写该方法,这种方式放行的一个资源是单独生成一条过滤器链,都不会走认证授权那条过滤器链的。如:
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers("/swagger**/**")
.antMatchers("/webjars/**")
.antMatchers("/v3/**")
.antMatchers("/doc.html");
}
public C antMatchers(String... antPatterns) {
Assert.state(!this.anyRequestConfigured, "Can't configure antMatchers after anyRequest");
return chainRequestMatchers(RequestMatchers.antMatchers(antPatterns));
}
@Override
protected IgnoredRequestConfigurer chainRequestMatchers(List<RequestMatcher> requestMatchers) {
WebSecurity.this.ignoredRequests.addAll(requestMatchers);
return this;
}
上面这个方法会添加多个RequestMatchers
放到WebSecurity
对象中的ignoredRequests
属性中。
4.3、PerformBuild方法
protected Filter performBuild() throws Exception {
Assert.state(!this.securityFilterChainBuilders.isEmpty(),
() -> "At least one SecurityBuilder<? extends SecurityFilterChain> needs to be specified. "
+ "Typically this is done by exposing a SecurityFilterChain bean "
+ "or by adding a @Configuration that extends WebSecurityConfigurerAdapter. "
+ "More advanced users can invoke " + WebSecurity.class.getSimpleName()
+ ".addSecurityFilterChainBuilder directly");
int chainSize = this.ignoredRequests.size() + this.securityFilterChainBuilders.size();
List<SecurityFilterChain> securityFilterChains = new ArrayList<>(chainSize);
List<RequestMatcherEntry<List<WebInvocationPrivilegeEvaluator>>> requestMatcherPrivilegeEvaluatorsEntries = new ArrayList<>();
for (RequestMatcher ignoredRequest : this.ignoredRequests) {
WebSecurity.this.logger.warn("You are asking Spring Security to ignore " + ignoredRequest
+ ". This is not recommended -- please use permitAll via HttpSecurity#authorizeHttpRequests instead.");
SecurityFilterChain securityFilterChain = new DefaultSecurityFilterChain(ignoredRequest);
securityFilterChains.add(securityFilterChain);
requestMatcherPrivilegeEvaluatorsEntries
.add(getRequestMatcherPrivilegeEvaluatorsEntry(securityFilterChain));
}
for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : this.securityFilterChainBuilders) {
SecurityFilterChain securityFilterChain = securityFilterChainBuilder.build();
securityFilterChains.add(securityFilterChain);
requestMatcherPrivilegeEvaluatorsEntries
.add(getRequestMatcherPrivilegeEvaluatorsEntry(securityFilterChain));
}
if (this.privilegeEvaluator == null) {
this.privilegeEvaluator = new RequestMatcherDelegatingWebInvocationPrivilegeEvaluator(
requestMatcherPrivilegeEvaluatorsEntries);
}
FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
if (this.httpFirewall != null) {
filterChainProxy.setFirewall(this.httpFirewall);
}
if (this.requestRejectedHandler != null) {
filterChainProxy.setRequestRejectedHandler(this.requestRejectedHandler);
}
filterChainProxy.afterPropertiesSet();
Filter result = filterChainProxy;
if (this.debugEnabled) {
this.logger.warn("\n\n" + "********************************************************************\n"
+ "********** Security debugging is enabled. *************\n"
+ "********** This may include sensitive information. *************\n"
+ "********** Do not use in a production system! *************\n"
+ "********************************************************************\n\n");
result = new DebugFilter(filterChainProxy);
}
this.postBuildAction.run();
return result;
}
4.3.1、断言
先断言securityFilterChainBuilders
集合是否为空,为空的话直接报错!然后新建一个过滤器链集合securityFilterChains
,集合的初始容量是ignoredRequests
集合和securityFilterChainBuilders
集合数量之和。
4.3.2、遍历ignoredRequests集合生成多个过滤器链
循环遍历ignoredRequests
集合,这个集合中的数据在上面configure
方法执行完后就已经被填充。一个放行资源会生成一条过滤器链,然后添加到securityFilterChains
过滤器链集合。
4.3.3、遍历securityFilterChainBuilders集合生成多个过滤器链
接着开始循环遍历securityFilterChainBuilders
集合,这个集合中的数据在上面init
方法执行完后就会把我们自定义后的HttpSecurity
添加到该集合中。遍历该集合,让该集合中的每一项去执行build
方法,即让HttpSecurity
对象去执行build
方法,然后返回一条过滤器链添加到securityFilterChains
过滤器链集合中。
那么HttpSecurity
对象是怎么构建出一条过滤器链出来的呢?让我们继续跟踪源码!发现HttpSecurity
执行build
方法的时候又来到了我们最熟悉的AbstractConfiguredSecurityBuilder#dobuild
方法,然后又是老三样,开始执行init``configure
和performBuild
方法,外加上beforeConfigure
方法。
4.3.3.1、init方法
还是和以前一样,循环遍历configurers
集合,执行每个xxxConfigurer
的init
方法。在前面WebSecurity
对象执行init
时就已经将默认的配置类和自定义的配置类(重写WebSecurityConfigurerAdapter#config(http)
方法)放到了该集合中。configurers
集合中的xxxConfigurer
就不一一分析了,就以FormLoginConfigurer
为例,看看它执行init
方法时干了啥?
@Override
public void init(H http) throws Exception {
super.init(http);
initDefaultLoginFilter(http);
}
@Override
public void init(B http) throws Exception {
updateAuthenticationDefaults();
updateAccessDefaults(http);
registerDefaultAuthenticationEntryPoint(http);
}
先执行了父类AbstractAuthenticationFilterConfigurer
中的init
方法。
- 给当前的
UsernamePasswordAuthenticationFilter
过滤器配置默认的登录处理地址,失败跳转地址,注销成功跳转地址。 - 对登录页,登录处理地址和失败跳转地址放行。
- 注册异常处理器
然后再执行initDefaultLoginFilter
方法,如果从当前的HttpSecurity
中获取到默认登录页生成过滤器并且没有自定义登录页面,那么就重新配置默认登录页生成过滤器中的参数。
private void initDefaultLoginFilter(H http) {
DefaultLoginPageGeneratingFilter loginPageGeneratingFilter = http
.getSharedObject(DefaultLoginPageGeneratingFilter.class);
if (loginPageGeneratingFilter != null && !isCustomLoginPage()) {
loginPageGeneratingFilter.setFormLoginEnabled(true);
loginPageGeneratingFilter.setUsernameParameter(getUsernameParameter());
loginPageGeneratingFilter.setPasswordParameter(getPasswordParameter());
loginPageGeneratingFilter.setLoginPageUrl(getLoginPage());
loginPageGeneratingFilter.setFailureUrl(getFailureUrl());
loginPageGeneratingFilter.setAuthenticationUrl(getLoginProcessingUrl());
}
}
4.3.3.2、beforeConfigure方法
@Override
protected void beforeConfigure() throws Exception {
if (this.authenticationManager != null) {
setSharedObject(AuthenticationManager.class, this.authenticationManager);
}
else {
setSharedObject(AuthenticationManager.class, getAuthenticationRegistry().build());
}
}
private AuthenticationManagerBuilder getAuthenticationRegistry() {
return getSharedObject(AuthenticationManagerBuilder.class);
}
大家还记得在前面new``HttpSecurity
的时候传入了一个AuthenticationManagerBuilder
对象对吧,不记得可以在4.1.1.2章节处查看,使用获取出来的AuthenticationManagerBuilder
对象执行build
方法,不用多想,构建出来的对象就是ProviderManager
对象,然后将ProviderManager
存入共享对象中。
4.3.3.3、configure方法
还是和以前一样,循环遍历configurers
集合,执行每个xxxConfigurer
的configure
方法。以FormLoginConfigurer
为例,看看它执行configure
方法时干了啥?
public void configure(B http) throws Exception {
PortMapper portMapper = http.getSharedObject(PortMapper.class);
if (portMapper != null) {
this.authenticationEntryPoint.setPortMapper(portMapper);
}
RequestCache requestCache = http.getSharedObject(RequestCache.class);
if (requestCache != null) {
this.defaultSuccessHandler.setRequestCache(requestCache);
}
this.authFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class));
this.authFilter.setAuthenticationSuccessHandler(this.successHandler);
this.authFilter.setAuthenticationFailureHandler(this.failureHandler);
if (this.authenticationDetailsSource != null) {
this.authFilter.setAuthenticationDetailsSource(this.authenticationDetailsSource);
}
SessionAuthenticationStrategy sessionAuthenticationStrategy = http
.getSharedObject(SessionAuthenticationStrategy.class);
if (sessionAuthenticationStrategy != null) {
this.authFilter.setSessionAuthenticationStrategy(sessionAuthenticationStrategy);
}
RememberMeServices rememberMeServices = http.getSharedObject(RememberMeServices.class);
if (rememberMeServices != null) {
this.authFilter.setRememberMeServices(rememberMeServices);
}
F filter = postProcess(this.authFilter);
http.addFilter(filter);
}
它的configure
在其父类中被实现。从HttpSecuriy
的共享对象中取出AuthenticationManager
对象,即我们在上一步存入进去的ProviderManager
对象。然后重要的就是给该UsernamePasswordAuthenticationFilter
设置认证成功处理器,认证失败处理器,记住我服务,然后注册到Spring容器,最后的最后就是将配置好的过滤器添加到HttpSecurity
对象中。
至此,大家可以通过使用FormLoginConfigurer
如何创建出UsernamePasswordAuthenticationFilter
过滤器,来自己推导出HttpSecurity
中其他xxxCofigurer
是如何创建出其他过滤器的,这样一来,都将创建好的过滤器放入到HttpSecurity
对象中的filters
属性中。
4.3.3.4、performBuild方法
@Override
protected DefaultSecurityFilterChain performBuild() {
this.filters.sort(OrderComparator.INSTANCE);
List<Filter> sortedFilters = new ArrayList<>(this.filters.size());
for (Filter filter : this.filters) {
sortedFilters.add(((OrderedFilter) filter).filter);
}
return new DefaultSecurityFilterChain(this.requestMatcher, sortedFilters);
}
将filters
集合中的过滤器按照顺序排好,然后放入到新建的DefaultSecurityFilterChain
过滤器链中,即一个过滤器链由多个过滤器组合而成,并返回。
4.3.4、生成FilterChainProxy
经过上面的步骤之后,会将生成的过滤器链全部添加到securityFilterChains
集合中,在new``FilterChainProxy
的时候将过滤器链集合securityFilterChains
传入其中,这就和上面的一个FilterChainProxy
管理着多个过滤器链不谋而合。给FilterChainProxy
对象配置防火墙,并返回。