- 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>> extends
SecurityBuilder<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
方法。@Override
protected 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);
}
@Override
public 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
方法,构建出来一个过滤器链:@Override
protected 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 implements
SecurityConfigurer<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 implements
ObjectPostProcessor<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
的灵魂。@Override
public void init(B http) throws Exception {
updateAuthenticationDefaults();
updateAccessDefaults(http);
registerDefaultAuthenticationEntryPoint(http);
}
init
方法只要干了三件事:updateAuthenticationDefaults
方法主要是配置默认的登录处理地址,失败跳转地址,注销成功跳转地址。updateAccessDefaults
方法主要是对登录页,登录处理地址和失败跳转地址默认进行permitAll
配置(如果用户配置permitAll=true的话)。registerDefaultAuthenticationEntryPoint
方法则是注册异常处理器。
再来看下configure
方法:
@Override
public 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>> extends
AbstractAuthenticationFilterConfigurer<H, FormLoginConfigurer<H>, UsernamePasswordAuthenticationFilter> {
FormLoginCongurer
继承自AbstractAuthenticationFilterConfigurer
类,明确了AbstractAuthenticationFilterConfigurer
中的泛型是UsernamePasswordAuthenticationFilter
,也就是说FormLoginCongurer
最终要配置的是UsernamePasswordAuthenticationFilter
过滤器。FormLoginCongurer
重写了init
方法,配置了一下默认的登录页面,其他的基本上都来自父类,未做太多改变。
另外我们日常配置的很多东西都来自这里:
好啦,这就是FormLoginCongurer
这个配置类,用于配置UsernamePasswordAuthenticationFilter
过滤器。其他的xxxConfigurer
十分类似,每个xxxConfigurer
都对应了一个不同的Filter
。