- 1、配置与构建分离
- 1.1、构建
- 1.2、配置
- 1.2.1、SecuriryConfigurer
- 1.2.2、GlobalAuthenticationConfigurerAdapter
- 1.2.3、WebSecurityConfigurer
- 1.2.4、SecurityConfigurerAdapter
- 1.2.4.1、UserDetailsAwareConfigurer
- 1.2.4.2、AbstractDaoAuthenticationConfigurer
- 1.2.4.3、UserDetailsServiceConfigurer
- 1.2.4.4、UserDetailsManagerConfigurer
- 1.2.4.5、JdbcUserDetailsManagerConfigurer
- 1.2.4.6、InMemoryUserDetailsManagerConfigurer
- 1.2.4.7、AbstractHttpConfigurer
- 1.2.4.8、AbstractAuthenticationFilterConfigurer📌
- 1.2.4.9、FormLoginConfigurer📌
1、配置与构建分离
作为一个框架,尤其是安全框架,配置必须足够灵活才能使用于更多的业务场景。Spring Security采取了配置与构建分离的架构设计来保证这一点。配置只需去收集配置项,构建只需要把所有的配置构建成目标对象。各干各的,分离职责,这种做法能够提高代码的可维护性和可读写性。Spring Security利用接口隔离把配置和构建进行高度抽象,提高灵活度,降低复杂度。不过这个体系依然十分庞大。为了降低学习难度,需要把大问题拆解成小问题,各个击破,这种学习方法在学习一些复杂的抽象理论时很奏效。
1.1、构建
1.1.1、SecurityBuilder
SecurityBuilder就是对构建的抽象。
public interface SecurityBuilder<O> {O build() throws Exception;}
1.1.2、HttpSecurityBuilder
HttpSecurityBuilder是一个接口,继承自SecurityBuilder接口,其中泛型为DefaultSecurityFilterChain,那么HttpSecurityBuilder接口的作用就是对DefaultSecurityFilterChain的构建进行了增强,为其构建增加了一些额外的获取配置和管理配置的入口。
public interface HttpSecurityBuilder<H extends HttpSecurityBuilder<H>> extendsSecurityBuilder<DefaultSecurityFilterChain> {<C extends SecurityConfigurer<DefaultSecurityFilterChain, H>> C getConfigurer(Class<C> clazz);<C extends SecurityConfigurer<DefaultSecurityFilterChain, H>> C removeConfigurer(Class<C> clazz);<C> void setSharedObject(Class<C> sharedType, C object);<C> C getSharedObject(Class<C> sharedType);H authenticationProvider(AuthenticationProvider authenticationProvider);H userDetailsService(UserDetailsService userDetailsService) throws Exception;H addFilterAfter(Filter filter, Class<? extends Filter> afterFilter);H addFilterBefore(Filter filter, Class<? extends Filter> beforeFilter);H addFilter(Filter filter);}
getConfigurer方法用于获取一个配置对象。Spring Security过滤器中的所有过滤器对象都是由xxxConfigurer来进行配置的,这里就是用于获取xxxConfigurer对象。removeConfigurer方法用于移除一个配置对象。setSharedObject和getSharedObject方法用于配置或获取由多个SecurityConfigurer共享的对象。authenticationProvider方法用于配置认证验证器。userDetailsService方法用于配置数据源接口。addFilterAfter方法用于在某一个过滤器之后添加过滤器。addFilterBefore方法用于在某一个过滤器之前添加过滤器。addFilter方法用于添加一个过滤器,该过滤器必须是现有过滤器链中的某一个过滤器或其扩展。
HttpSecurityBuilder接口定义的这些方法在HttpSecurity中都将得到实现。
1.1.3、AbstractSecurityBuilder
AbstractSecurityBuilder是对SecurityBuilder的实现。源码如下:
public abstract class AbstractSecurityBuilder<O> implements SecurityBuilder<O> {private AtomicBoolean building = new AtomicBoolean();private O object;public final O build() throws Exception {if (this.building.compareAndSet(false, true)) {// 构建的核心逻辑由钩子方法提供this.object = doBuild();return this.object;}throw new AlreadyBuiltException("This object has already been built");}// 构建目标对象public final O getObject() {if (!this.building.get()) {throw new IllegalStateException("This object has not been built");}return this.object;}// 钩子方法protected abstract O doBuild() throws Exception;}
可以看到,这里重写了build方法,并加了final关键字,不可覆写!在build方法中,通过原子类AtomicBoolean对构建方法build方法进行了调用限制:每个目标对象只能被构建一次,避免安全策略发生不一致的情况。构建的核心逻辑通过预留的钩子方法doBuild来扩展,钩子方法是很常见的一种继承策略,将来在子类中实现具体逻辑。AbstractSecurityBuilder还提供了获取已构建目标对象的方法getObject。
1.1.4、AbstractConfiguredSecurityBuilder
AbstractConfiguredSecurityBuilder是AbstractSecurityBuilder的子类。AbstractConfiguredSecurityBuilder定义了一个枚举类,将整个构建过程分为5种状态,也可以理解为构建过程生命周期的五个阶段,如下:
private enum BuildState {UNBUILT(0),INITIALIZING(1),CONFIGURING(2),BUILDING(3),BUILT(4);private final int order;BuildState(int order) {this.order = order;}public boolean isInitializing() {return INITIALIZING.order == order;}public boolean isConfigured() {return order >= CONFIGURING.order;}}
五种状态分别是UNBUILT``INITIALIZING``CONFIGURING``BUILDING以及BUILT。另外还提供了两个判断方法,isInitializing判断是否正在初始化阶段,isConfigured表示是否已经构建完成。AbstractConfiguredSecurityBuilder中的方法比较多,在这里只列出两个关键的方法:
第一个方法就是这个
add方法,这相当于在收集所有的配置。将所有的xxxConfigurer收集起来存储到configurers中,将来再统一初始化并配置。configurers本身是一个LinkedHashMap,key 是配置类的 class,value 是xxxConfigurer配置类集合。当需要对这些配置类进行集中配置的时候,会通过getConfigurers方法获取配置类集合,这个获取过程就是就是把LinkedHashMap中的 value 拿出来,放到一个集合中返回。private <C extends SecurityConfigurer<O, B>> void add(C configurer) {Assert.notNull(configurer, "configurer cannot be null");Class<? extends SecurityConfigurer<O, B>> clazz = (Class<? extends SecurityConfigurer<O, B>>) configurer.getClass();synchronized (configurers) {if (buildState.isConfigured()) {throw new IllegalStateException("Cannot apply " + configurer+ " to already built object");}List<SecurityConfigurer<O, B>> configs = allowConfigurersOfSameType ? this.configurers.get(clazz) : null;if (configs == null) {configs = new ArrayList<>(1);}configs.add(configurer);this.configurers.put(clazz, configs);if (buildState.isInitializing()) {this.configurersAddedInInitializing.add(configurer);}}}private Collection<SecurityConfigurer<O, B>> getConfigurers() {List<SecurityConfigurer<O, B>> result = new ArrayList<>();for (List<SecurityConfigurer<O, B>> configs : this.configurers.values()) {result.addAll(configs);}return result;}
另一个方法就是
doBuild方法。在AbstractSecurityBuilder类中,构建的核心逻辑被放到doBuild方法上,但是AbstractSecurityBuilder类中只是定义了抽象的doBuild方法,真正的实现还是在该类中的doBuild方法。@Overrideprotected final O doBuild() throws Exception {synchronized (configurers) {buildState = BuildState.INITIALIZING;beforeInit();init();buildState = BuildState.CONFIGURING;beforeConfigure();configure();buildState = BuildState.BUILDING;O result = performBuild();buildState = BuildState.BUILT;return result;}}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 : configurersAddedInInitializing) {configurer.init((B) this);}}private void configure() throws Exception {Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();for (SecurityConfigurer<O, B> configurer : configurers) {configurer.configure((B) this);}}
doBuild方法就是一边更新状态一边进行构建。beforeInit是一个预留方法,没有任何实现;init方法就是找到所有的xxxConfigurer,挨个调用其init方法进行初始化;beforeConfigure是一个预留方法,没有任何实现;configure方法就是找到所有的xxxConfigurer,挨个调用其configure方法进行配置;performBuild方法是真正的过滤器链构建方法,但是在当前AbstractConfiguredSecurityBuilder中的performBuild方法只是一个抽象方法,具体的实现在HttpSecurity类中。1.1.5、HttpSecurity📌
public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain, HttpSecurity>implements SecurityBuilder<DefaultSecurityFilterChain>, HttpSecurityBuilder<HttpSecurity> {}
其中,
HttpSecurity的继承关系图:
可以看到,HttpSecurity继承自AbstractConfiguredSecurityBuilder,同时实现了SecurityBuilder和HttpSecurityBuilder两个接口。
结合上面HttpSecurity的源码,HttpSecurity实现SecurityBuilder接口时传入的泛型为DefaultSecurityFilterChain,那么可以很清楚的知道HttpSecurity就是用来构建DefaultSecurityFilterChain对象的了。1.1.5.1、DefaultSecurityFilterChain
那么
DefaultSecurityFilterChain是什么呢🤔?相信大家看过前面的Spring Security过滤器架构(源码篇)
文章,知道SecurityFilterChain是我们平时所说的过滤器链。public interface SecurityFilterChain {boolean matches(HttpServletRequest request);List<Filter> getFilters();}
SecurityFilterChain接口中只定义了两个方法,一个是matches方法用来匹配请求;另外一个是getFilters方法返回一个List集合,集合中放着Filter对象。当一个请求到来时,用matches方法去比较请求是否和当前过滤器链吻合,如果吻合,那么当前请求会逐个经过getFilters方法返回的List集合中的过滤器。SecurityFilterChain接口只有一个实现类,那就是DefaultSecurityFilterChain:public final class DefaultSecurityFilterChain implements SecurityFilterChain {private static final Log logger = LogFactory.getLog(DefaultSecurityFilterChain.class);private final RequestMatcher requestMatcher;private final List<Filter> filters;public DefaultSecurityFilterChain(RequestMatcher requestMatcher, Filter... filters) {this(requestMatcher, Arrays.asList(filters));}public DefaultSecurityFilterChain(RequestMatcher requestMatcher, List<Filter> filters) {logger.info("Creating filter chain: " + requestMatcher + ", " + filters);this.requestMatcher = requestMatcher;this.filters = new ArrayList<>(filters);}public RequestMatcher getRequestMatcher() {return requestMatcher;}public List<Filter> getFilters() {return filters;}public boolean matches(HttpServletRequest request) {return requestMatcher.matches(request);}@Overridepublic String toString() {return "[ " + requestMatcher + ", " + filters + "]";}}
DefaultSecurityFilterChain只是对SecurityFilterChain中的方法进行了实现,并没有特别值得说的地方。从上面的介绍中,大家可以看到,DefaultSecurityFilterChain其实就相当于Spring Security 中的过滤器链,一个DefaultSecurityFilterChain代表一个过滤器链,如果系统中存在多个过滤器链,则会存在多个DefaultSecurityFilterChain对象。1.1.5.2、HttpSecurity
HttpSecurity做的事情就是进行各种各样的xxxConfigurer配置。如:public CorsConfigurer<HttpSecurity> cors() throws Exception {return getOrApply(new CorsConfigurer<>());}public CsrfConfigurer<HttpSecurity> csrf() throws Exception {ApplicationContext context = getContext();return getOrApply(new CsrfConfigurer<>(context));}public FormLoginConfigurer<HttpSecurity> formLogin() throws Exception {return getOrApply(new FormLoginConfigurer<>());}public ExceptionHandlingConfigurer<HttpSecurity> exceptionHandling() throws Exception {return getOrApply(new ExceptionHandlingConfigurer<>());}
HttpSecurity中有大量类似的方法,可以在此处对过滤器中的过滤器一个一个进行配置。
每个配置方法的结尾都会使用getOrApply方法,这个方法是干嘛的呢?🤔private <C extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity>> C getOrApply(C configurer) throws Exception {C existingConfig = (C) getConfigurer(configurer.getClass());if (existingConfig != null) {return existingConfig;}return apply(configurer);}
getConfigurer方法是在它的父类AbstractConfiguredSecurityBuilder中定义的,目的是就是去查看当前这个xxxConfigurer是否已经配置过了。如果当前xxxConfigurer已经配置过了,则直接返回,否则调用apply方法,这个apply方法最终会调用父类AbstractConfiguredSecurityBuilder中的add方法,将当前xxxConfigurer配置收集起来。HttpSecurity中还有一个addFilter方法:public HttpSecurity addFilter(Filter filter) {Class<? extends Filter> filterClass = filter.getClass();if (!comparator.isRegistered(filterClass)) {throw new IllegalArgumentException("The Filter class "+ filterClass.getName()+ " does not have a registered order and cannot be added without a specified order. Consider using addFilterBefore or addFilterAfter instead.");}this.filters.add(filter);return this;}
这个
addFilter方法的作用主要是在各个xxxConfigurer进行配置的时候,会调用这个方法,(xxxConfigurer就是用来配置过滤器的),把Filter过滤器都添加到filters变量中。如在1.2.4.8章节中的AbstractAuthenticationFilterConfigurer的configure方法中就被用到,将配置好的UsernamePasswordAuthenticationFilter过滤器添加到filters变量中。
最终在HttpSecurity重写父类performBuild方法,构建出来一个过滤器链:@Overrideprotected DefaultSecurityFilterChain performBuild() {filters.sort(comparator);return new DefaultSecurityFilterChain(requestMatcher, filters);}
先给过滤器排序,然后构造出
DefaultSecurityFilterChain过滤器链。1.2、配置
1.2.1、SecuriryConfigurer
SecuriryConfigurer本身是一个接口:public interface SecurityConfigurer<O, B extends SecurityBuilder<O>> {void init(B builder) throws Exception;void configure(B builder) throws Exception;}
可以看到,
SecuriryConfigurer中主要定义了两个方法:init初始化方法和configure配置方法。这里只是规范了方法的定义,具体的实现则在不同的实现类中。
需要注意的是这两个方法的参数类型都是一个泛型B,也就是SecurityBuilder的子类,关于SecurityBuilder,在上面的章节已经介绍过了。SecuriryConfigurer有三个实现类:
- GlobalAuthenticationConfigurerAdapter
- WebScurityConfigurer
-
1.2.2、GlobalAuthenticationConfigurerAdapter
GlobalAuthenticationConfigurerAdapter实现了SecuriryConfigurer接口,但是并未对方法做具体的实现,只是将泛型具体化了。@Order(100)public abstract class GlobalAuthenticationConfigurerAdapter implementsSecurityConfigurer<AuthenticationManager, AuthenticationManagerBuilder> {public void init(AuthenticationManagerBuilder auth) throws Exception {}public void configure(AuthenticationManagerBuilder auth) throws Exception {}}
可以看到,
SecurityConfigurer中的泛型,现在明确成了AuthenticationManager和AuthenticationManagerBuilder。所以GlobalAuthenticationConfigurerAdapter的实现类主要是和配置AuthenticationManager有关。当然也包括默认的用户名和密码也是由它的实现类进行配置的。1.2.3、WebSecurityConfigurer
这个接口其实就是我们天天用的
WebSecurityConfigurerAdapter类所实现的接口,所以WebSecurityConfigurer的作用就非常明确了,用于用户扩展自定义配置。1.2.4、SecurityConfigurerAdapter
SecurityConfigurerAdapter实现了SecuriryConfigurer接口,我们使用的大部分xxxConfigurer全都是SecurityConfigurerAdapter的子类。SecurityConfigurerAdapter在SecuriryConfigurer的基础上,还扩展出了几个非常好用的方法:public abstract class SecurityConfigurerAdapter<O, B extends SecurityBuilder<O>>implements SecurityConfigurer<O, B> {private B securityBuilder;private CompositeObjectPostProcessor objectPostProcessor = new CompositeObjectPostProcessor();public void init(B builder) throws Exception {}public void configure(B builder) throws Exception {}public B and() {return getBuilder();}protected final B getBuilder() {if (securityBuilder == null) {throw new IllegalStateException("securityBuilder cannot be null");}return securityBuilder;}@SuppressWarnings("unchecked")protected <T> T postProcess(T object) {return (T) this.objectPostProcessor.postProcess(object);}public void addObjectPostProcessor(ObjectPostProcessor<?> objectPostProcessor) {this.objectPostProcessor.addObjectPostProcessor(objectPostProcessor);}public void setBuilder(B builder) {this.securityBuilder = builder;}private static final class CompositeObjectPostProcessor implementsObjectPostProcessor<Object> {private List<ObjectPostProcessor<?>> postProcessors = new ArrayList<>();@SuppressWarnings({ "rawtypes", "unchecked" })public Object postProcess(Object object) {for (ObjectPostProcessor opp : postProcessors) {Class<?> oppClass = opp.getClass();Class<?> oppType = GenericTypeResolver.resolveTypeArgument(oppClass,ObjectPostProcessor.class);if (oppType == null || oppType.isAssignableFrom(object.getClass())) {object = opp.postProcess(object);}}return object;}private boolean addObjectPostProcessor(ObjectPostProcessor<?> objectPostProcessor) {boolean result = this.postProcessors.add(objectPostProcessor);postProcessors.sort(AnnotationAwareOrderComparator.INSTANCE);return result;}}}
- 首先一开始声明了一个
CompositeObjectPostProcessor实例,CompositeObjectPostProcessor是ObjectPostProcessor的一个实现,ObjectPostProcessor本身是一个后置处理器,该后置处理器默认有两个实现,AutowireBeanFactoryObjectPostProcessor和CompositeObjectPostProcessor。其中,AutowireBeanFactoryObjectPostProcessor主要是利用了AutowireCapableBeanFactory对Bean进行手动注册,因为在Spring Secuirty 中,很多对象都是手动 new 出来的,这个 new 出来的对象和容器没有任何关系,利用AutowireCapableBeanFactory可以将这些手动 new 出来的对象注入到容器中,AutowireBeanFactoryObjectPostProcessor的主要作用就是完成这件事;CompositeObjectPostProcessor则是一个复合的对象处理器,里面维护了一个list集合,这个list集合中,大部分情况下只存储一条数据,那就是AutowireBeanFactoryObjectPostProcessor用来完成对象注入到容器的操作,如果用户手动调用了addObjectPostProcessor方法,那么CompositeObjectPostProcessor集合中维护的数据就会多出来一条,在CompositeObjectPostProcessor#postProcess方法中,会遍历集合中的所有ObjectPostProcessor,挨个调用postProcess方法对对象进行后置处理。😵晕,这里看不懂有什么用,我们继续让下看!!! and方法,该方法返回值是一个SecurityBuilder,SecurityBuilder实际上就是HttpSecurity,我们在HttpSecurity中去配置不同过滤器时,可以使用and方法进行链式配置,就是因为这里定义了and方法并返回了SecurityBuilder实例。
SecurityConfigurerAdapter也有几个主要的子类:
- UserDetailsAwareConfigurer
-
1.2.4.1、UserDetailsAwareConfigurer
1.2.4.2、AbstractDaoAuthenticationConfigurer
AbstractDaoAuthenticationConfigurer中所做的事情比较简单,主要是构造了一个默认的DaoAuthenticationProvider,并为其配置PasswordEncoder和UserDetailsService。1.2.4.3、UserDetailsServiceConfigurer
UserDetailsServiceConfigurer重写了AbstractDaoAuthenticationConfigurer中的configure方法,在configure方法执行之前加入了initUserDetailsService方法,以方便按照自己的方式去初始化UserDetailsService。不过这里的initUserDetailsService方法是一个空方法。1.2.4.4、UserDetailsManagerConfigurer
UserDetailsManagerConfigurer中实现了UserDetailsServiceConfigurer中定义的initUserDetailsService方法,具体的实现逻辑就是将UserDetailsBuilder所构建出来的UserDetails以及提前准备好的UserDetails中的用户存储到UserDetailsService中。
该类同时添加了withUser方法用来添加用户,同时还增加了一个UserDetailsBuilder用来构建用户。1.2.4.5、JdbcUserDetailsManagerConfigurer
JdbcUserDetailsManagerConfigurer在父类的基础上补充了DataSource对象,同时还提供了相应的数据库查询方法。1.2.4.6、InMemoryUserDetailsManagerConfigurer
InMemoryUserDetailsManagerConfigurer在父类的基础上重写了构造方法,将父类中的UserDetailsService实例定义为InMemoryUserDetailsManager。
📌上面的内容简单来说就是:上面的配置类在执行configure方法的时候,使用 new 出来的UserDetailsManager创建用户。如InMemoryUserDetailsManagerConfigurer就使用InMemoryUserDetailsManager创建用户存到内存当中。1.2.4.7、AbstractHttpConfigurer
AbstractHttpConfigurer这一派中的东西非常多,我们所有的过滤器配置,都是它的子类。
AbstractHttpConfigurer继承自SecurityConfigurerAdapter,并增加了两个方法,disable方法和withObjectPostProcessor方法:public abstract class AbstractHttpConfigurer<T extends AbstractHttpConfigurer<T, B>, B extends HttpSecurityBuilder<B>>extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, B> {/*** Disables the {@link AbstractHttpConfigurer} by removing it. After doing so a fresh* version of the configuration can be applied.** @return the {@link HttpSecurityBuilder} for additional customizations*/@SuppressWarnings("unchecked")public B disable() {getBuilder().removeConfigurer(getClass());return getBuilder();}@SuppressWarnings("unchecked")public T withObjectPostProcessor(ObjectPostProcessor<?> objectPostProcessor) {addObjectPostProcessor(objectPostProcessor);return (T) this;}}
- 我们常用的
.csrf().disable()就是出自这里,其实disable的实现原理就是从getBuilder中移除相关的xxxConfigurer。getBuilder方法实际上获取到的是HttpSecurity,所以移除掉xxxConfigurer实际上就是从过滤器链中移除某一个过滤器,例如.csrf().disable()就是移除掉处理csrf的过滤器。 另一个增加的方法是
withObjectPostProcessor,这是为配置类手动添加后置处理器的。在AbstractHttpConfigurer的父类中其实有一个类似的方法就是addObjectPostProcessor,但是addObjectPostProcessor只是一个添加方法,返回值为void,而withObjectPostProcessor的返回值是当前配置类,也就是xxxConfigurer,所以使用withObjectPostProcessor方法的话,就可以使用链式配置。1.2.4.8、AbstractAuthenticationFilterConfigurer📌
AbstractAuthenticationFilterConfigurer类中的功能比较多,源码也是相当长,不过我们只需要抓住两点,init方法和configure方法,因为这两个方法是所有xxxConfigurer的灵魂。@Overridepublic void init(B http) throws Exception {updateAuthenticationDefaults();updateAccessDefaults(http);registerDefaultAuthenticationEntryPoint(http);}
init方法只要干了三件事:updateAuthenticationDefaults方法主要是配置默认的登录处理地址,失败跳转地址,注销成功跳转地址。updateAccessDefaults方法主要是对登录页,登录处理地址和失败跳转地址默认进行permitAll配置(如果用户配置permitAll=true的话)。registerDefaultAuthenticationEntryPoint方法则是注册异常处理器。
再来看下configure方法:
@Overridepublic void configure(B http) throws Exception {PortMapper portMapper = http.getSharedObject(PortMapper.class);if (portMapper != null) {authenticationEntryPoint.setPortMapper(portMapper);}RequestCache requestCache = http.getSharedObject(RequestCache.class);if (requestCache != null) {this.defaultSuccessHandler.setRequestCache(requestCache);}authFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class));authFilter.setAuthenticationSuccessHandler(successHandler);authFilter.setAuthenticationFailureHandler(failureHandler);if (authenticationDetailsSource != null) {authFilter.setAuthenticationDetailsSource(authenticationDetailsSource);}SessionAuthenticationStrategy sessionAuthenticationStrategy = http.getSharedObject(SessionAuthenticationStrategy.class);if (sessionAuthenticationStrategy != null) {authFilter.setSessionAuthenticationStrategy(sessionAuthenticationStrategy);}RememberMeServices rememberMeServices = http.getSharedObject(RememberMeServices.class);if (rememberMeServices != null) {authFilter.setRememberMeServices(rememberMeServices);}F filter = postProcess(authFilter);http.addFilter(filter);}
configure方法中的逻辑很简单,构建各种各样的回调函数给authFilter,其实就是UsernamePasswordAuthenticationFilter,authFilter再去postProcess中走一圈注册到Spring容器中,最后再把authFilter添加到过滤器链中。
1.2.4.9、FormLoginConfigurer📌
public final class FormLoginConfigurer<H extends HttpSecurityBuilder<H>> extendsAbstractAuthenticationFilterConfigurer<H, FormLoginConfigurer<H>, UsernamePasswordAuthenticationFilter> {
FormLoginCongurer继承自AbstractAuthenticationFilterConfigurer类,明确了AbstractAuthenticationFilterConfigurer中的泛型是UsernamePasswordAuthenticationFilter,也就是说FormLoginCongurer最终要配置的是UsernamePasswordAuthenticationFilter过滤器。FormLoginCongurer重写了init方法,配置了一下默认的登录页面,其他的基本上都来自父类,未做太多改变。
另外我们日常配置的很多东西都来自这里:
好啦,这就是FormLoginCongurer这个配置类,用于配置UsernamePasswordAuthenticationFilter过滤器。其他的xxxConfigurer十分类似,每个xxxConfigurer都对应了一个不同的Filter。
