1、配置与构建分离

作为一个框架,尤其是安全框架,配置必须足够灵活才能使用于更多的业务场景。Spring Security采取了配置与构建分离的架构设计来保证这一点。配置只需去收集配置项,构建只需要把所有的配置构建成目标对象。各干各的,分离职责,这种做法能够提高代码的可维护性和可读写性。Spring Security利用接口隔离把配置和构建进行高度抽象,提高灵活度,降低复杂度。不过这个体系依然十分庞大。为了降低学习难度,需要把大问题拆解成小问题,各个击破,这种学习方法在学习一些复杂的抽象理论时很奏效。

1.1、构建

1.1.1、SecurityBuilder

SecurityBuilder就是对构建的抽象。

  1. public interface SecurityBuilder<O> {
  2. O build() throws Exception;
  3. }

就一个动作,构建泛化的目标对象O

1.1.2、HttpSecurityBuilder

HttpSecurityBuilder是一个接口,继承自SecurityBuilder接口,其中泛型为DefaultSecurityFilterChain,那么HttpSecurityBuilder接口的作用就是对DefaultSecurityFilterChain的构建进行了增强,为其构建增加了一些额外的获取配置和管理配置的入口。

  1. public interface HttpSecurityBuilder<H extends HttpSecurityBuilder<H>> extends
  2. SecurityBuilder<DefaultSecurityFilterChain> {
  3. <C extends SecurityConfigurer<DefaultSecurityFilterChain, H>> C getConfigurer(
  4. Class<C> clazz);
  5. <C extends SecurityConfigurer<DefaultSecurityFilterChain, H>> C removeConfigurer(
  6. Class<C> clazz);
  7. <C> void setSharedObject(Class<C> sharedType, C object);
  8. <C> C getSharedObject(Class<C> sharedType);
  9. H authenticationProvider(AuthenticationProvider authenticationProvider);
  10. H userDetailsService(UserDetailsService userDetailsService) throws Exception;
  11. H addFilterAfter(Filter filter, Class<? extends Filter> afterFilter);
  12. H addFilterBefore(Filter filter, Class<? extends Filter> beforeFilter);
  13. H addFilter(Filter filter);
  14. }
  1. getConfigurer方法用于获取一个配置对象。Spring Security过滤器中的所有过滤器对象都是由xxxConfigurer来进行配置的,这里就是用于获取xxxConfigurer对象。
  2. removeConfigurer方法用于移除一个配置对象。
  3. setSharedObjectgetSharedObject方法用于配置或获取由多个SecurityConfigurer共享的对象。
  4. authenticationProvider方法用于配置认证验证器。
  5. userDetailsService方法用于配置数据源接口。
  6. addFilterAfter方法用于在某一个过滤器之后添加过滤器。
  7. addFilterBefore方法用于在某一个过滤器之前添加过滤器。
  8. addFilter方法用于添加一个过滤器,该过滤器必须是现有过滤器链中的某一个过滤器或其扩展。

HttpSecurityBuilder接口定义的这些方法在HttpSecurity中都将得到实现。

1.1.3、AbstractSecurityBuilder

AbstractSecurityBuilder是对SecurityBuilder的实现。源码如下:

  1. public abstract class AbstractSecurityBuilder<O> implements SecurityBuilder<O> {
  2. private AtomicBoolean building = new AtomicBoolean();
  3. private O object;
  4. public final O build() throws Exception {
  5. if (this.building.compareAndSet(false, true)) {
  6. // 构建的核心逻辑由钩子方法提供
  7. this.object = doBuild();
  8. return this.object;
  9. }
  10. throw new AlreadyBuiltException("This object has already been built");
  11. }
  12. // 构建目标对象
  13. public final O getObject() {
  14. if (!this.building.get()) {
  15. throw new IllegalStateException("This object has not been built");
  16. }
  17. return this.object;
  18. }
  19. // 钩子方法
  20. protected abstract O doBuild() throws Exception;
  21. }

可以看到,这里重写了build方法,并加了final关键字,不可覆写!在build方法中,通过原子类AtomicBoolean对构建方法build方法进行了调用限制:每个目标对象只能被构建一次,避免安全策略发生不一致的情况。构建的核心逻辑通过预留的钩子方法doBuild来扩展,钩子方法是很常见的一种继承策略,将来在子类中实现具体逻辑。AbstractSecurityBuilder还提供了获取已构建目标对象的方法getObject

1.1.4、AbstractConfiguredSecurityBuilder

AbstractConfiguredSecurityBuilderAbstractSecurityBuilder的子类。
AbstractConfiguredSecurityBuilder定义了一个枚举类,将整个构建过程分为5种状态,也可以理解为构建过程生命周期的五个阶段,如下:

  1. private enum BuildState {
  2. UNBUILT(0),
  3. INITIALIZING(1),
  4. CONFIGURING(2),
  5. BUILDING(3),
  6. BUILT(4);
  7. private final int order;
  8. BuildState(int order) {
  9. this.order = order;
  10. }
  11. public boolean isInitializing() {
  12. return INITIALIZING.order == order;
  13. }
  14. public boolean isConfigured() {
  15. return order >= CONFIGURING.order;
  16. }
  17. }

五种状态分别是UNBUILT``INITIALIZING``CONFIGURING``BUILDING以及BUILT。另外还提供了两个判断方法,isInitializing判断是否正在初始化阶段,isConfigured表示是否已经构建完成。
AbstractConfiguredSecurityBuilder中的方法比较多,在这里只列出两个关键的方法:

  1. 第一个方法就是这个add方法,这相当于在收集所有的配置。将所有的xxxConfigurer收集起来存储到configurers中,将来再统一初始化并配置。configurers本身是一个LinkedHashMap,key 是配置类的 class,value 是xxxConfigurer配置类集合。当需要对这些配置类进行集中配置的时候,会通过getConfigurers方法获取配置类集合,这个获取过程就是就是把LinkedHashMap中的 value 拿出来,放到一个集合中返回。

    1. private <C extends SecurityConfigurer<O, B>> void add(C configurer) {
    2. Assert.notNull(configurer, "configurer cannot be null");
    3. Class<? extends SecurityConfigurer<O, B>> clazz = (Class<? extends SecurityConfigurer<O, B>>) configurer
    4. .getClass();
    5. synchronized (configurers) {
    6. if (buildState.isConfigured()) {
    7. throw new IllegalStateException("Cannot apply " + configurer
    8. + " to already built object");
    9. }
    10. List<SecurityConfigurer<O, B>> configs = allowConfigurersOfSameType ? this.configurers
    11. .get(clazz) : null;
    12. if (configs == null) {
    13. configs = new ArrayList<>(1);
    14. }
    15. configs.add(configurer);
    16. this.configurers.put(clazz, configs);
    17. if (buildState.isInitializing()) {
    18. this.configurersAddedInInitializing.add(configurer);
    19. }
    20. }
    21. }
    22. private Collection<SecurityConfigurer<O, B>> getConfigurers() {
    23. List<SecurityConfigurer<O, B>> result = new ArrayList<>();
    24. for (List<SecurityConfigurer<O, B>> configs : this.configurers.values()) {
    25. result.addAll(configs);
    26. }
    27. return result;
    28. }
  2. 另一个方法就是doBuild方法。在AbstractSecurityBuilder类中,构建的核心逻辑被放到doBuild方法上,但是AbstractSecurityBuilder类中只是定义了抽象的doBuild方法,真正的实现还是在该类中的doBuild方法。

    1. @Override
    2. protected final O doBuild() throws Exception {
    3. synchronized (configurers) {
    4. buildState = BuildState.INITIALIZING;
    5. beforeInit();
    6. init();
    7. buildState = BuildState.CONFIGURING;
    8. beforeConfigure();
    9. configure();
    10. buildState = BuildState.BUILDING;
    11. O result = performBuild();
    12. buildState = BuildState.BUILT;
    13. return result;
    14. }
    15. }
    16. private void init() throws Exception {
    17. Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();
    18. for (SecurityConfigurer<O, B> configurer : configurers) {
    19. configurer.init((B) this);
    20. }
    21. for (SecurityConfigurer<O, B> configurer : configurersAddedInInitializing) {
    22. configurer.init((B) this);
    23. }
    24. }
    25. private void configure() throws Exception {
    26. Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();
    27. for (SecurityConfigurer<O, B> configurer : configurers) {
    28. configurer.configure((B) this);
    29. }
    30. }

    doBuild方法就是一边更新状态一边进行构建。
    beforeInit是一个预留方法,没有任何实现;init方法就是找到所有的xxxConfigurer,挨个调用其init方法进行初始化;beforeConfigure是一个预留方法,没有任何实现;configure方法就是找到所有的xxxConfigurer,挨个调用其configure方法进行配置;performBuild方法是真正的过滤器链构建方法,但是在当前AbstractConfiguredSecurityBuilder中的performBuild方法只是一个抽象方法,具体的实现在HttpSecurity类中。

    1.1.5、HttpSecurity📌

    1. public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain, HttpSecurity>
    2. implements SecurityBuilder<DefaultSecurityFilterChain>, HttpSecurityBuilder<HttpSecurity> {
    3. }

    其中,HttpSecurity的继承关系图:
    image.png
    可以看到,HttpSecurity继承自AbstractConfiguredSecurityBuilder,同时实现了SecurityBuilderHttpSecurityBuilder两个接口。
    结合上面HttpSecurity的源码,HttpSecurity实现SecurityBuilder接口时传入的泛型为DefaultSecurityFilterChain,那么可以很清楚的知道HttpSecurity就是用来构建DefaultSecurityFilterChain对象的了。

    1.1.5.1、DefaultSecurityFilterChain

    那么DefaultSecurityFilterChain是什么呢🤔?相信大家看过前面的Spring Security过滤器架构(源码篇)
    文章,知道SecurityFilterChain是我们平时所说的过滤器链。

    1. public interface SecurityFilterChain {
    2. boolean matches(HttpServletRequest request);
    3. List<Filter> getFilters();
    4. }

    SecurityFilterChain接口中只定义了两个方法,一个是matches方法用来匹配请求;另外一个是getFilters方法返回一个List集合,集合中放着Filter对象。当一个请求到来时,用matches方法去比较请求是否和当前过滤器链吻合,如果吻合,那么当前请求会逐个经过getFilters方法返回的List集合中的过滤器。
    SecurityFilterChain接口只有一个实现类,那就是DefaultSecurityFilterChain

    1. public final class DefaultSecurityFilterChain implements SecurityFilterChain {
    2. private static final Log logger = LogFactory.getLog(DefaultSecurityFilterChain.class);
    3. private final RequestMatcher requestMatcher;
    4. private final List<Filter> filters;
    5. public DefaultSecurityFilterChain(RequestMatcher requestMatcher, Filter... filters) {
    6. this(requestMatcher, Arrays.asList(filters));
    7. }
    8. public DefaultSecurityFilterChain(RequestMatcher requestMatcher, List<Filter> filters) {
    9. logger.info("Creating filter chain: " + requestMatcher + ", " + filters);
    10. this.requestMatcher = requestMatcher;
    11. this.filters = new ArrayList<>(filters);
    12. }
    13. public RequestMatcher getRequestMatcher() {
    14. return requestMatcher;
    15. }
    16. public List<Filter> getFilters() {
    17. return filters;
    18. }
    19. public boolean matches(HttpServletRequest request) {
    20. return requestMatcher.matches(request);
    21. }
    22. @Override
    23. public String toString() {
    24. return "[ " + requestMatcher + ", " + filters + "]";
    25. }
    26. }

    DefaultSecurityFilterChain只是对SecurityFilterChain中的方法进行了实现,并没有特别值得说的地方。从上面的介绍中,大家可以看到,DefaultSecurityFilterChain其实就相当于Spring Security 中的过滤器链,一个DefaultSecurityFilterChain代表一个过滤器链,如果系统中存在多个过滤器链,则会存在多个DefaultSecurityFilterChain对象。

    1.1.5.2、HttpSecurity

    HttpSecurity做的事情就是进行各种各样的xxxConfigurer配置。如:

    1. public CorsConfigurer<HttpSecurity> cors() throws Exception {
    2. return getOrApply(new CorsConfigurer<>());
    3. }
    4. public CsrfConfigurer<HttpSecurity> csrf() throws Exception {
    5. ApplicationContext context = getContext();
    6. return getOrApply(new CsrfConfigurer<>(context));
    7. }
    8. public FormLoginConfigurer<HttpSecurity> formLogin() throws Exception {
    9. return getOrApply(new FormLoginConfigurer<>());
    10. }
    11. public ExceptionHandlingConfigurer<HttpSecurity> exceptionHandling() throws Exception {
    12. return getOrApply(new ExceptionHandlingConfigurer<>());
    13. }

    HttpSecurity中有大量类似的方法,可以在此处对过滤器中的过滤器一个一个进行配置。
    每个配置方法的结尾都会使用getOrApply方法,这个方法是干嘛的呢?🤔

    1. private <C extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity>> C getOrApply(
    2. C configurer) throws Exception {
    3. C existingConfig = (C) getConfigurer(configurer.getClass());
    4. if (existingConfig != null) {
    5. return existingConfig;
    6. }
    7. return apply(configurer);
    8. }

    getConfigurer方法是在它的父类AbstractConfiguredSecurityBuilder中定义的,目的是就是去查看当前这个xxxConfigurer是否已经配置过了。如果当前xxxConfigurer已经配置过了,则直接返回,否则调用apply方法,这个apply方法最终会调用父类AbstractConfiguredSecurityBuilder中的add方法,将当前xxxConfigurer配置收集起来。
    HttpSecurity中还有一个addFilter方法:

    1. public HttpSecurity addFilter(Filter filter) {
    2. Class<? extends Filter> filterClass = filter.getClass();
    3. if (!comparator.isRegistered(filterClass)) {
    4. throw new IllegalArgumentException(
    5. "The Filter class "
    6. + filterClass.getName()
    7. + " does not have a registered order and cannot be added without a specified order. Consider using addFilterBefore or addFilterAfter instead.");
    8. }
    9. this.filters.add(filter);
    10. return this;
    11. }

    这个addFilter方法的作用主要是在各个xxxConfigurer进行配置的时候,会调用这个方法,(xxxConfigurer就是用来配置过滤器的),把Filter过滤器都添加到filters变量中。如在1.2.4.8章节中的AbstractAuthenticationFilterConfigurerconfigure方法中就被用到,将配置好的UsernamePasswordAuthenticationFilter过滤器添加到filters变量中。
    最终在HttpSecurity重写父类performBuild方法,构建出来一个过滤器链:

    1. @Override
    2. protected DefaultSecurityFilterChain performBuild() {
    3. filters.sort(comparator);
    4. return new DefaultSecurityFilterChain(requestMatcher, filters);
    5. }

    先给过滤器排序,然后构造出DefaultSecurityFilterChain过滤器链。

    1.2、配置

    1.2.1、SecuriryConfigurer

    SecuriryConfigurer本身是一个接口:

    1. public interface SecurityConfigurer<O, B extends SecurityBuilder<O>> {
    2. void init(B builder) throws Exception;
    3. void configure(B builder) throws Exception;
    4. }

    可以看到,SecuriryConfigurer中主要定义了两个方法:init初始化方法和configure配置方法。这里只是规范了方法的定义,具体的实现则在不同的实现类中。
    需要注意的是这两个方法的参数类型都是一个泛型B,也就是SecurityBuilder的子类,关于SecurityBuilder,在上面的章节已经介绍过了。
    SecuriryConfigurer有三个实现类:

  • GlobalAuthenticationConfigurerAdapter
  • WebScurityConfigurer
  • SecurityConfigurerAdapter

    1.2.2、GlobalAuthenticationConfigurerAdapter

    GlobalAuthenticationConfigurerAdapter实现了SecuriryConfigurer接口,但是并未对方法做具体的实现,只是将泛型具体化了。

    1. @Order(100)
    2. public abstract class GlobalAuthenticationConfigurerAdapter implements
    3. SecurityConfigurer<AuthenticationManager, AuthenticationManagerBuilder> {
    4. public void init(AuthenticationManagerBuilder auth) throws Exception {
    5. }
    6. public void configure(AuthenticationManagerBuilder auth) throws Exception {
    7. }
    8. }

    可以看到,SecurityConfigurer中的泛型,现在明确成了AuthenticationManagerAuthenticationManagerBuilder。所以GlobalAuthenticationConfigurerAdapter的实现类主要是和配置AuthenticationManager有关。当然也包括默认的用户名和密码也是由它的实现类进行配置的。

    1.2.3、WebSecurityConfigurer

    这个接口其实就是我们天天用的WebSecurityConfigurerAdapter类所实现的接口,所以WebSecurityConfigurer的作用就非常明确了,用于用户扩展自定义配置。

    1.2.4、SecurityConfigurerAdapter

    SecurityConfigurerAdapter实现了SecuriryConfigurer接口,我们使用的大部分xxxConfigurer全都是SecurityConfigurerAdapter的子类。
    SecurityConfigurerAdapterSecuriryConfigurer的基础上,还扩展出了几个非常好用的方法:

    1. public abstract class SecurityConfigurerAdapter<O, B extends SecurityBuilder<O>>
    2. implements SecurityConfigurer<O, B> {
    3. private B securityBuilder;
    4. private CompositeObjectPostProcessor objectPostProcessor = new CompositeObjectPostProcessor();
    5. public void init(B builder) throws Exception {
    6. }
    7. public void configure(B builder) throws Exception {
    8. }
    9. public B and() {
    10. return getBuilder();
    11. }
    12. protected final B getBuilder() {
    13. if (securityBuilder == null) {
    14. throw new IllegalStateException("securityBuilder cannot be null");
    15. }
    16. return securityBuilder;
    17. }
    18. @SuppressWarnings("unchecked")
    19. protected <T> T postProcess(T object) {
    20. return (T) this.objectPostProcessor.postProcess(object);
    21. }
    22. public void addObjectPostProcessor(ObjectPostProcessor<?> objectPostProcessor) {
    23. this.objectPostProcessor.addObjectPostProcessor(objectPostProcessor);
    24. }
    25. public void setBuilder(B builder) {
    26. this.securityBuilder = builder;
    27. }
    28. private static final class CompositeObjectPostProcessor implements
    29. ObjectPostProcessor<Object> {
    30. private List<ObjectPostProcessor<?>> postProcessors = new ArrayList<>();
    31. @SuppressWarnings({ "rawtypes", "unchecked" })
    32. public Object postProcess(Object object) {
    33. for (ObjectPostProcessor opp : postProcessors) {
    34. Class<?> oppClass = opp.getClass();
    35. Class<?> oppType = GenericTypeResolver.resolveTypeArgument(oppClass,
    36. ObjectPostProcessor.class);
    37. if (oppType == null || oppType.isAssignableFrom(object.getClass())) {
    38. object = opp.postProcess(object);
    39. }
    40. }
    41. return object;
    42. }
    43. private boolean addObjectPostProcessor(
    44. ObjectPostProcessor<?> objectPostProcessor) {
    45. boolean result = this.postProcessors.add(objectPostProcessor);
    46. postProcessors.sort(AnnotationAwareOrderComparator.INSTANCE);
    47. return result;
    48. }
    49. }
    50. }
  1. 首先一开始声明了一个CompositeObjectPostProcessor实例,CompositeObjectPostProcessorObjectPostProcessor的一个实现,ObjectPostProcessor本身是一个后置处理器,该后置处理器默认有两个实现,AutowireBeanFactoryObjectPostProcessorCompositeObjectPostProcessor。其中,AutowireBeanFactoryObjectPostProcessor主要是利用了AutowireCapableBeanFactoryBean进行手动注册,因为在Spring Secuirty 中,很多对象都是手动 new 出来的,这个 new 出来的对象和容器没有任何关系,利用AutowireCapableBeanFactory可以将这些手动 new 出来的对象注入到容器中,AutowireBeanFactoryObjectPostProcessor的主要作用就是完成这件事;CompositeObjectPostProcessor则是一个复合的对象处理器,里面维护了一个list集合,这个list集合中,大部分情况下只存储一条数据,那就是AutowireBeanFactoryObjectPostProcessor用来完成对象注入到容器的操作,如果用户手动调用了addObjectPostProcessor方法,那么CompositeObjectPostProcessor集合中维护的数据就会多出来一条,在CompositeObjectPostProcessor#postProcess方法中,会遍历集合中的所有ObjectPostProcessor,挨个调用postProcess方法对对象进行后置处理。😵晕,这里看不懂有什么用,我们继续让下看!!!
  2. and方法,该方法返回值是一个SecurityBuilderSecurityBuilder实际上就是HttpSecurity,我们在HttpSecurity中去配置不同过滤器时,可以使用and方法进行链式配置,就是因为这里定义了and方法并返回了SecurityBuilder实例。

SecurityConfigurerAdapter也有几个主要的子类:

  • UserDetailsAwareConfigurer
  • AbstractHttpConfigurer

    1.2.4.1、UserDetailsAwareConfigurer

    这个配置类看名字大概就是用来配置用户类的。
    深入理解Spring Security配置与构建(源码篇) - 图2

    1.2.4.2、AbstractDaoAuthenticationConfigurer

    AbstractDaoAuthenticationConfigurer中所做的事情比较简单,主要是构造了一个默认的DaoAuthenticationProvider,并为其配置PasswordEncoderUserDetailsService

    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这一派中的东西非常多,我们所有的过滤器配置,都是它的子类。
    深入理解Spring Security配置与构建(源码篇) - 图3
    AbstractHttpConfigurer继承自SecurityConfigurerAdapter,并增加了两个方法,disable方法和withObjectPostProcessor方法:

    1. public abstract class AbstractHttpConfigurer<T extends AbstractHttpConfigurer<T, B>, B extends HttpSecurityBuilder<B>>
    2. extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, B> {
    3. /**
    4. * Disables the {@link AbstractHttpConfigurer} by removing it. After doing so a fresh
    5. * version of the configuration can be applied.
    6. *
    7. * @return the {@link HttpSecurityBuilder} for additional customizations
    8. */
    9. @SuppressWarnings("unchecked")
    10. public B disable() {
    11. getBuilder().removeConfigurer(getClass());
    12. return getBuilder();
    13. }
    14. @SuppressWarnings("unchecked")
    15. public T withObjectPostProcessor(ObjectPostProcessor<?> objectPostProcessor) {
    16. addObjectPostProcessor(objectPostProcessor);
    17. return (T) this;
    18. }
    19. }
  1. 我们常用的.csrf().disable()就是出自这里,其实disable的实现原理就是从getBuilder中移除相关的xxxConfigurergetBuilder方法实际上获取到的是HttpSecurity,所以移除掉xxxConfigurer实际上就是从过滤器链中移除某一个过滤器,例如.csrf().disable()就是移除掉处理csrf的过滤器。
  2. 另一个增加的方法是withObjectPostProcessor,这是为配置类手动添加后置处理器的。在AbstractHttpConfigurer的父类中其实有一个类似的方法就是addObjectPostProcessor,但是addObjectPostProcessor只是一个添加方法,返回值为void,而withObjectPostProcessor的返回值是当前配置类,也就是xxxConfigurer,所以使用withObjectPostProcessor方法的话,就可以使用链式配置。

    1.2.4.8、AbstractAuthenticationFilterConfigurer📌

    AbstractAuthenticationFilterConfigurer类中的功能比较多,源码也是相当长,不过我们只需要抓住两点,init方法和configure方法,因为这两个方法是所有xxxConfigurer的灵魂。

    1. @Override
    2. public void init(B http) throws Exception {
    3. updateAuthenticationDefaults();
    4. updateAccessDefaults(http);
    5. registerDefaultAuthenticationEntryPoint(http);
    6. }

    init方法只要干了三件事:

  3. updateAuthenticationDefaults方法主要是配置默认的登录处理地址,失败跳转地址,注销成功跳转地址。

  4. updateAccessDefaults方法主要是对登录页,登录处理地址和失败跳转地址默认进行permitAll配置(如果用户配置permitAll=true的话)。
  5. registerDefaultAuthenticationEntryPoint方法则是注册异常处理器。

再来看下configure方法:

  1. @Override
  2. public void configure(B http) throws Exception {
  3. PortMapper portMapper = http.getSharedObject(PortMapper.class);
  4. if (portMapper != null) {
  5. authenticationEntryPoint.setPortMapper(portMapper);
  6. }
  7. RequestCache requestCache = http.getSharedObject(RequestCache.class);
  8. if (requestCache != null) {
  9. this.defaultSuccessHandler.setRequestCache(requestCache);
  10. }
  11. authFilter.setAuthenticationManager(http
  12. .getSharedObject(AuthenticationManager.class));
  13. authFilter.setAuthenticationSuccessHandler(successHandler);
  14. authFilter.setAuthenticationFailureHandler(failureHandler);
  15. if (authenticationDetailsSource != null) {
  16. authFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
  17. }
  18. SessionAuthenticationStrategy sessionAuthenticationStrategy = http
  19. .getSharedObject(SessionAuthenticationStrategy.class);
  20. if (sessionAuthenticationStrategy != null) {
  21. authFilter.setSessionAuthenticationStrategy(sessionAuthenticationStrategy);
  22. }
  23. RememberMeServices rememberMeServices = http
  24. .getSharedObject(RememberMeServices.class);
  25. if (rememberMeServices != null) {
  26. authFilter.setRememberMeServices(rememberMeServices);
  27. }
  28. F filter = postProcess(authFilter);
  29. http.addFilter(filter);
  30. }

configure方法中的逻辑很简单,构建各种各样的回调函数给authFilter,其实就是UsernamePasswordAuthenticationFilterauthFilter再去postProcess中走一圈注册到Spring容器中,最后再把authFilter添加到过滤器链中。

1.2.4.9、FormLoginConfigurer📌

  1. public final class FormLoginConfigurer<H extends HttpSecurityBuilder<H>> extends
  2. AbstractAuthenticationFilterConfigurer<H, FormLoginConfigurer<H>, UsernamePasswordAuthenticationFilter> {

FormLoginCongurer继承自AbstractAuthenticationFilterConfigurer类,明确了AbstractAuthenticationFilterConfigurer中的泛型是UsernamePasswordAuthenticationFilter,也就是说FormLoginCongurer最终要配置的是UsernamePasswordAuthenticationFilter过滤器。
FormLoginCongurer重写了init方法,配置了一下默认的登录页面,其他的基本上都来自父类,未做太多改变。
另外我们日常配置的很多东西都来自这里:
深入理解Spring Security配置与构建(源码篇) - 图4
好啦,这就是FormLoginCongurer这个配置类,用于配置UsernamePasswordAuthenticationFilter过滤器。其他的xxxConfigurer十分类似,每个xxxConfigurer都对应了一个不同的Filter