Spring Security 源码分析九:Java config - HttpSecurity & SecurityConfigurer

栏目: 后端 · 发布时间: 5年前

内容简介:本文是对 Spring Security Core 4.0.4 Release 进行源码分析的系列文章之一;本系列开始,将讲解有关 Spring Security 的配置相关的内容;本文为作者的原创作品,转载需注明出处;

本文是对 Spring Security Core 4.0.4 Release 进行源码分析的系列文章之一;

本系列开始,将讲解有关 Spring Security 的配置相关的内容;

本文为作者的原创作品,转载需注明出处;

简介

在《 Spring Security 源码分析九:Java config - WebSecurity & @EnableWebSecurity 》文中,笔者在HttpSecurity 小节中留了一个悬念,那就是通过 HttpSecurity 的 build() 方法将返回一个SecurityFilterChain 对象,SecurityFilterChain 对象由多个 Filter 所构成,组成了一条 Spring Security 的过滤链,但是并没有深入的去探讨 HttpSecurity 是如何去构建 SecurityFilterChain 对象的内部机制;本篇文章,笔者将试图去回答这个问题;

配置用例

先来看一些简单的用例,

单个 FilterChain 的配置

protected void configure(HttpSecurity http) throws Exception {
      http
          .authorizeRequests()
          .anyRequest().authenticated()
        .and()
          .formLogin()
        .and()
          .httpBasic();
}

等价于做了如下的配置

<http>
    <intercept-url pattern="/**" access="authenticated"/>
    <form-login />
    <http-basic />
</http>
  • 每一个 and() 操作符就相当于 XML 配置中的一次换行,XML 配置中的每一行代表一个完整的配置;
  • 配置 .authorizeRequests().anyRequest().authenticated() 相当于

    <intercept-url pattern="/**" access="authenticated"/>
    

    authorizeRequests()表示开始一个 <intercept-url> 配置节点的开始;

    anyRequest()表示配置属性 pattern=”/**“;

    authenticated()表示配置属性 access=”authenticated”;

上述的配置等价于配置了一个 SecurityFilterChain 对象,既是一个 Spring Security 安全链,因为没有指定安全链的起始链接,所以该安全链默认作用在 /** 访问 request 上的,并且使用默认实现的 form login 和 http basic authentication 对象;

多个 FilterChain 的配置

Spring Security 源码分析八:Spring Security 过滤链二 - Demo 例子 的例子中,通过 Java Config 的方式配置了两条不同的 Security Filter Chain;

首先,通过如下的方式配置了一条 /web/** 的安全过滤链,

http.antMatcher("/web/**") // the filter chain defined for web request
    .authorizeRequests()
       .antMatchers("/web/report/**").hasRole("MANAGER")
       .anyRequest().authenticated()
    .and()
    .formLogin()
    // login 的相对路径必须与 security chain 的的相对路径吻合,这里是 /web/**;注意 login 分两步,一步是 Getter 会到 login.html,另外一步是从 login.html -> post -> 6
    // 允许访问
    .permitAll();

再次,通过如下的方式配置了另一条 /rest/** 的安全过滤链,

http.antMatcher("/rest/**") // the filter chain defined for web request;
    .csrf().disable() // rest 请求无需 CSRF Token;
    .authorizeRequests()
       .antMatchers("/rest/hello").hasRole("USER")
       .anyRequest().authenticated()
    .and()
       .httpBasic();

上述的配置等价如下的配置,

<bean id="filterChainProxy" class="org.springframework.security.web.FilterChainProxy">
  <sec:filter-chain-map path-type="ant">
     <sec:filter-chain pattern="/web/**" filters="
           securityContextPersistenceFilter,
           logoutFilter,
           usernamePasswordAuthenticationFilter,
           exceptionTranslationFilter,
           filterSecurityInterceptor">
       <sec:intercept-url pattern="/web/report/**" access="ROLE_MANAGER"/> 
     </sec:filter-chain>      
     <sec:filter-chain pattern="/rest/**" filters="
           securityContextPersistenceFilter,
           logoutFilter,
           basicAuthenticationFilter,
           exceptionTranslationFilter,
           filterSecurityInterceptor" >
        <sec:intercept-url pattern="/rest/report/**" access="ROLE_USER"/>    
      </sec:filter-chain>     
  </sec:filter-chain-map>
</bean>

<!-- logout filter -->
<bean id="logoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">
<!-- the post-logout destination -->
  <constructor-arg value="/"/>
  <constructor-arg> 
      <array>
          <ref local="logoutHandler"/> 
          <!--高级配置 添加 rememberMe-->
          <ref local="rememberMeServices"/>
      </array>
  </constructor-arg>
  <property name="filterProcessesUrl" value="/logout"/>
</bean>

<bean id="basicAuthenticationFilter" ....>

......

</bean>

......

相关配置说明和其它配置元素

还是以上述单个 FilterChain 的配置为例

http -> HttpSecurity

Java Config 中的配置元素http等价于 XML 配置元素中的<http>;该实例既表示 HttpSecurity 实例本身;

and() : HttpSecurity

Java Config 中的配置元素and()等价于 XML 配置元素中的 换行 操作,也就表示准备要开始配置另外一个 Security 元素了;其实在 Java Config 的过程中,每一次的 and() 操作以后,返回的都是当前 HttpSecuirty 实例;可以看到,每一次相关方法的调用,比如、、返回的都是一个 SecurityConfigurer 对象,而通过调用 SecurityConfigurer.and() 返回的永远都是 SecurityBuilder 对象,这里对应的既是 HttpSecurity;

该部分将会在后面的部分有更详细的介绍;

antMatcher(String antPattern) : HttpSecurity

Java Config 中的配置元素antMatcher(antPattern)类似于进行如下的 XML 配置,

<sec:filter-chain pattern="/web/**" ... > 
 ....
</sec:filter-chain>

开启了一个新的 Security Chain 的配置;

authorizeRequests() : ExpressionUrlAuthorizationConfigurer

Java Config 中的配置元素authorizeRequests()等价于 XML 配置元素中的<intercept-url>操作,表示对特定 URL 执行的特定操作;这个方法比较有意思,返回的是 ExpressionUrlAuthorizationConfigurer<HttpSecurity>. ExpressionInterceptUrlRegistry 一个内嵌对象;该部分将会在后面的部分有更详细的介绍;

formLogin() : FormLoginConfigurer

Java Config 中的配置元素formLogin()等价于 XML 配置元素中的<form-login>操作,表示对特定 URL 执行的特定操作;该方法返回的是 FormLoginConfigurer 对象,该部分将会在后面的部分有更详细的介绍;

httpBasic() : HttpBasicConfigurer

Java Config 中的配置元素httpBasic()等价于 XML 配置元素中的<http-basic>操作;该方法返回的是 HttpBasicConfigurer 对象,该部分将会在后面的部分有更详细的介绍;

sessionManagement() : SessionManagementConfigurer

Java Config 中的配置元素sessionManagement()类似于进行如下的 XML 配置,

<session-management>
  <concurrency-control max-sessions="1" error-if-maximum-exceeded="true" />
</session-management>

该方法返回的是 SessionManagementConfigurer 对象,该部分将会在后面的部分有更详细的介绍;

authenticationProvider( authenticationProvider ) : HttpSecurity

Java Config 中的配置元素authenticationProvider( authenticationProvider )类似于进行如下的 XML 配置,

<authentication-manager>
   <authentication-provider user-service-ref='myUserDetailsService'/>
</authentication-manager>

该方法返回的是当前的 HttpSecurity 对象;

userDetailsService( userDetailsService ) : HttpSecurity

Java Config 中的配置元素userDetailsService()类似于进行如下的 XML 的配置,

<beans:bean id="myUserDetailsService" class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">
   <beans:property name="dataSource" ref="dataSource"/>
</beans:bean>

portMapper() : PortMapperConfigurer

Java Config 中的配置元素portMapper()类似于进行如下的 XML 配置,

<port-mappings>
   <port-mapping http="9080" https="9443"/>
</port-mappings>

exceptionHandling() : ExceptionHandlingConfigurer

Java Config 中的配置元素exceptionHandling()类似于进行如下的 XML 的配置,

<bean id="exceptionTranslationFilter"
   class="org.springframework.security.web .access.ExceptionTranslationFilter"> 
   <property name="authenticationEntryPoint" ref="authenticationEntryPoint"/> 
   <property name="accessDeniedHandler" ref="accessDeniedHandler"/>
</bean>

<bean id="authenticationEntryPoint"
   class="org.springframework.security.web .authentication.LoginUrlAuthenticationEntryPoint"> 
   <property name="loginFormUrl" value="/login.do"/>
</bean>
<bean id="accessDeniedHandler"
   class="org.springframework.security.web .access.AccessDeniedHandlerImpl">
   <property name="errorPage" value="/accessDenied.do"/> 
</bean>

从 ExceptionHandlingConfigurer 的配置方法 configure() 中也可以看到这个逻辑,

@Override
public void configure(H http) throws Exception {
   AuthenticationEntryPoint entryPoint = getAuthenticationEntryPoint(http);
   ExceptionTranslationFilter exceptionTranslationFilter = new ExceptionTranslationFilter(
         entryPoint, getRequestCache(http));
   if (accessDeniedHandler != null) {
      exceptionTranslationFilter.setAccessDeniedHandler(accessDeniedHandler);
   }
   exceptionTranslationFilter = postProcess(exceptionTranslationFilter);
   http.addFilter(exceptionTranslationFilter);
}

其它配置

Spring Security 源码分析九:Java config - HttpSecurity & SecurityConfigurer

如图,展示了 HttpSecuirty 所有相关的配置项,里面还包含 csrf()logout()anonymous()requiresChannel() 等等非常重要的一系列的配置方法;

References

有关 XML 的配置参考 https://docs.spring.io/spring-security/site/docs/3.0.x/reference/ns-config.html

HttpSecurity

Spring Security 源码分析九:Java config - HttpSecurity & SecurityConfigurer

SecurityBuilder 的实体类总共有三个,HttpSecurity、WebSecurity 以及 AuthenticationManagerBuilder;下面笔者将逐个的分析每一个相关的类;

SecurityBuilder

SecurityBuilder 接口非常的简单,提供了一个 build() 方法,顾名思义,主要是用来执行构建操作的;

public interface SecurityBuilder<O> {

   /**
    * Builds the object and returns it or null.
    *
    * @return the Object to be built or null if the implementation allows it.
    * @throws Exception if an error occurred when building the Object
    */
   O build() throws Exception;
}

构建完成以后,将会返回对象 O;

AbstractSecurityBuilder

public abstract class AbstractSecurityBuilder<O> implements SecurityBuilder<O> {
   private AtomicBoolean building = new AtomicBoolean();

   private O object;

   public final O build() throws Exception {
      if (building.compareAndSet(false, true)) {
         object = doBuild();
         return object;
      }
      throw new AlreadyBuiltException("This object has already been built");
   }

   /**
    * @return the Object that was built
    */
   public final O getObject() {
      if (!building.get()) {
         throw new IllegalStateException("This object has not been built");
      }
      return object;
   }

   protected abstract O doBuild() throws Exception;
}

三个方法,

  • build()

    执行构建动作,通过调用抽象方法 build() 完成构建;

  • getObject()

    获得构建成功以后的对象;

  • doBuild()

    抽象方法,供子类实现其构建方法;

AbstractConfiguredSecurityBuilder

该抽象类中的逻辑非常的关键了,将其核心关键代码摘要如下,

public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBuilder<O>> 
   extends AbstractSecurityBuilder<O> {
   
   ......

   @SuppressWarnings("unchecked")
   public <C extends SecurityConfigurerAdapter<O, B>> C apply(C configurer)
         throws Exception {
      configurer.addObjectPostProcessor(objectPostProcessor);
      configurer.setBuilder((B) this);
      add(configurer);
      return configurer;
   }

   public <C extends SecurityConfigurer<O, B>> C apply(C configurer) throws Exception {
      add(configurer);
      return configurer;
   }
   
   ......

   /**
    * Sets an object that is shared by multiple {@link SecurityConfigurer}.
    *
    * @param sharedType the Class to key the shared object by.
    * @param object the Object to store
    */
   @SuppressWarnings("unchecked")
   public <C> void setSharedObject(Class<C> sharedType, C object) {
      this.sharedObjects.put((Class<Object>) sharedType, object);
   }

   @SuppressWarnings("unchecked")
   public <C> C getSharedObject(Class<C> sharedType) {
      return (C) this.sharedObjects.get(sharedType);
   }

   ......

   @SuppressWarnings("unchecked")
   private <C extends SecurityConfigurer<O, B>> void add(C configurer) throws Exception {

      Class<? extends SecurityConfigurer<O, B>> clazz = (Class<? extends SecurityConfigurer<O, B>>) configurer.getClass();

      synchronized (configurers) {

         ....

         List<SecurityConfigurer<O, B>> configs = allowConfigurersOfSameType ? this.configurers.get(clazz) : null;

         ....

         configs.add(configurer);
         this.configurers.put(clazz, configs);

         ....
      }

   }

   ......

   @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;
      }
   }

   ......

   /**
    * Subclasses must implement this method to build the object that is being returned.
    *
    * @return
    */
   protected abstract O performBuild() throws Exception;

   @SuppressWarnings("unchecked")
   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);
      }
   }   

   @SuppressWarnings("unchecked")
   private void configure() throws Exception {
      Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();

      for (SecurityConfigurer<O, B> configurer : configurers) {
         configurer.configure((B) this);
      }
   }

}

好些个核心的方法,下面我们一个一个的来屡吧,

  • apply(C configurer)

    这里笔者罗列了两个 apply(C configurer) 方法,目的是为了描述一个调试的 bug,HttpSecurity 的 getOrApply(configurer) 方法,

    @SuppressWarnings("unchecked")
    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);
    }
    

    如果通过 COMMAND + 鼠标左键点击 apply(configurer) 跳转到的是上述的方法

    public <C extends SecurityConfigurer<O, B>> C apply(C configurer) throws Exception {
       add(configurer);
       return configurer;
    }
    

    如果是这样的话,就有一个疑问了,那就是如果通过 configurer.and() 方法获得 HttpSecurity 既是上述的 Build 对象 B ,比如通过 http.csrf().and() 就无法获取 HttpSecurity 对象了,自然也就没有办法继续进行 HttpSecurity 的相关配置了;不过,经过笔者的调试过程中发现,实际上,经过 HttpSecurity.getOrApply(configurer) 方法调用的其实是

    @SuppressWarnings("unchecked")
    public <C extends SecurityConfigurerAdapter<O, B>> C apply(C configurer)
          throws Exception {
       configurer.addObjectPostProcessor(objectPostProcessor);
       configurer.setBuilder((B) this);
       add(configurer);
       return configurer;
    }
    

    该方法中,通过 configurer.setBuilder((B) this) 的方式将 HttpSecurity 赋值给了当前的 configurer,所以自然也就可以通过该 configurer 获取到当前的 HttpSecurity 对象了;Debug 过程的截图如下,可见,调用的正式上述方法;

    Spring Security 源码分析九:Java config - HttpSecurity & SecurityConfigurer
  • add(C configurer)

    该方法在 apply(C configurer) 方法中被调用,目的是将 configurer 添加到 builder 的 configurers 中;唯一需要注意的是,configurers 是一个以 configurer class 为 主键 的 Map,其值存储的就是按照 class 分类号的 configurers;为什么这样设计?难不成同一个类型的 configurer class 还会有多个 configurers?笔者暂时还没有想到相应的场景;

  • setSharedObject(Class

    sharedType, C object)

    当需要覆盖掉 configurer 的一些 工具 累的时候,可以使用这个方法;

  • doBuild() : O
    该方法是核心中的核心,执行构建完以后,将返回构建好的对象;笔者在前面分析 WebSecurity 的构建过程 中比较详细的描述了 WebSecurity 的三步构造过程,init、configure 以及 perform build 步骤;现在,我们再从源码的层面,依次看下这三个方法所执行的逻辑,

    • init build process

      对应前三行代码,

      buildState = BuildState.INITIALIZING;
      beforeInit();
      init();
      

      首先,执行 beforeInit() 方法,对应执行的是一个模板方法,子类需要继承并实现该方法来实现一些初始化之前的方法;如下所述,

      /**
       * Invoked prior to invoking each {@link SecurityConfigurer#init(SecurityBuilder)}
       * method. Subclasses may override this method to hook into the lifecycle  without
       * using a {@link SecurityConfigurer}.
       */
      protected void beforeInit() throws Exception {
      }
      

      再次,执行 init() 方法,

      @SuppressWarnings("unchecked")
      private void init() throws Exception {
         Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();
      
         for (SecurityConfigurer<O, B> configurer : configurers) {
           configurer.init((B) this);
         }
      
         ....
       
      }
      

      可以看到,在初始化构建过程当中,会首先依次执行各个 configurer 的 init() 方法;

    • configure build process

      这里的逻辑与 init build process 大同小异,同样是先执行模板方法 beforeConfigurer() 方法,需要子类继承实现;然后再依次遍历 configurer 并执行其 configurer() 方法;

    • perform build process

      这个过程执行抽象方法 performBuild(),该方法必须由子类实现;也就是说,三个子类 HttpSecurity、WebSecurity 以及 AuthenticationManagerBuilder 都有实现这个方法,这里,我们看看 HttpSecurity 的实现,

      @Override
      protected DefaultSecurityFilterChain performBuild() throws Exception {
         Collections.sort(filters, comparitor);
         return new DefaultSecurityFilterChain(requestMatcher, filters);
      }
      

      首先,根据 filters 的优先级排好序,然后通过构造好的 requestMatcher 和 filters 来初始化一个 DefaultSecurityFilterChain 对象并返回;

  • init()

    由 doBuild() 方法的 init build process 所调用;

  • configure()

    由 doBuild() 方法的 configure build process 所调用;

HttpSecurity

由可知,HttpSecurity 是一个 SecurityBuilder 实例,通过其父类AbstractConfiguredSecurityBuilderdoBuild() 方法的三步构建 init、configure 以及 perform build 最终返回一个 SecurityFilterChain 实例;可见,HttpSecurity 的职责就是通过一系列的 configurer 并且通过三步构建步骤最后生成一个 SecurityFilterChain 实例,该实例最终由 FilterChainProxy 加载;更多有关 HttpSecurity 构建的过程参考HttpSecurity.build 部分内容;

从HttpSecurity 相关配置元素和操作中,可以知道,HttpSecurity 通过各种配置方法注入了不同的 configurers,既对象,并且通过 getOrApply(configurer) 方法将 configurer 注入到父类的configurers队列中(注意是个 Map 对象),

@SuppressWarnings("unchecked")
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);
}

更多有关此部分的内容参考AbstractConfiguredSecurityBuilder中 apply(C configurer) 小节;另外这里 apply(configurer) 调用的是父类的第一个 apply(C configurer); 注意 ,正是因为在 apply 的过程中,将当前的 builder 既 HttpSecurity 对象注入到了 configurer 中,所以,可以通过任意的一个 configurer 对象通过调用其 and() 方法都可以获取到当前的 HttpSecurity 对象;就类似于在配置过程中通过 http.csrf().and() 既可以获取得到 HttpSecurity 对象;

Ok,通过上述分析,我们可以知道,HttpSecurity 通过若干 SecurityConfigurer 配置,通过其 configure() 方法,创建了若干个 Filters,正是这些 Filters 构成了 HttpSecurity 的核心,也正是这些 Filters 构建了 SecurityFilterChain 对象;那么,下面,我们就来一睹的风采;

SecurityConfigurer

Spring Security 源码分析九:Java config - HttpSecurity & SecurityConfigurer

由类图可知,SecurityConfigurer 主要分为两大类,WebSecurityConfigurer 和 SecurityConfigureAdapter;

注意,这里有一个关键的行为区别,那就是,WebSecurityConfigurerAdapter 类型的配置类,比如 WebConfigSecurity 和 RestConfigSecurity 不包含与之关联的 SecurityBuilder 实例,这里指的是 WebSecurity;而 SecurityConfigurerAdapter 类型的相关配置类则相反,均包含与其关联的 SecurityBuilder 类型实例,比如 AuthenticationManagerBuilder 以及 HttpSecurity,且是一对一的关系,这也就是为什么通过 SecurityConfigurerAdapter. and() 方法可以获取与之关联的 SecurityBuilder 的根本原因;

WebSecurityConfigurer

该部分参考 WebSecurity 章节的相关内容 WebSecurityConfigurer 的介绍;WebSecurityConfigurer 的主要职责就是扩展出用户自定义的有关 HttpSecurity 的配置;

SecurityConfigurerAdapter

由上述类图可知,包含三个子类,不过这里,笔者主要针对 UserDetailsAwareConfigurer 和 AbstractHttpConfigurer 来进行讲解;并且重要的是,该类提供了两个比较重要的方法;

  • and()

    该方法将会始终返回 HttpSecurity 对象;

  • getBuilder()

    and() 方法改回调用此方法来获取 Builder 对象,既 HttpSecurity 对象;

AbstractHttpConfigurer

由此类扩展出了多个与 HttpSecurity 相关联的 configurers,比如 HttpBasicConfigurer、FormLoginConfigurer 以及 ExpressionUrlAuthorizationConfigurer;

再来看一下,关注点聚焦到 HttpSecurity 上;

Spring Security 源码分析九:Java config - HttpSecurity & SecurityConfigurer

从HttpSecurity.build 的介绍可知 HttpSecurity 的构建的目的就是生成 Filters,然后将这些 Filters 作为构造参数初始化 DefaultSecurityFilterChain 对象并返回;而过程中,Filters 的生成就与 configurers 的方法 configure() 息息相关了;下面,笔者就相关的方法介绍如下,

HttpBasicConfigurer.configure(B http)

参数 B 指的是泛型 Builder,这里既是 HttpSecurity;

@Override
public void configure(B http) throws Exception {
   AuthenticationManager authenticationManager = http
         .getSharedObject(AuthenticationManager.class);
   BasicAuthenticationFilter basicAuthenticationFilter = new BasicAuthenticationFilter(
         authenticationManager, authenticationEntryPoint);
   if (authenticationDetailsSource != null) {
      basicAuthenticationFilter
            .setAuthenticationDetailsSource(authenticationDetailsSource);
   }
   RememberMeServices rememberMeServices = http.getSharedObject(RememberMeServices.class);
   if(rememberMeServices != null) {
      basicAuthenticationFilter.setRememberMeServices(rememberMeServices);
   }
   basicAuthenticationFilter = postProcess(basicAuthenticationFilter);
   http.addFilter(basicAuthenticationFilter);
}

下面笔者就 HttpBasicConfigurer 的配置的过程做进行详细的分析,

SharedObject
Filter

ExpressionUrlAuthorizationConfigurer

该对象的 configure 方法在其父类 AbstractInterceptUrlConfigurer 中,

@Override
public void configure(H http) throws Exception {
   FilterInvocationSecurityMetadataSource metadataSource = createMetadataSource(http);
   if (metadataSource == null) {
      return;
   }
   FilterSecurityInterceptor securityInterceptor = createFilterSecurityInterceptor(
         http, metadataSource, http.getSharedObject(AuthenticationManager.class));
   if (filterSecurityInterceptorOncePerRequest != null) {
      securityInterceptor
            .setObserveOncePerRequest(filterSecurityInterceptorOncePerRequest);
   }
   securityInterceptor = postProcess(securityInterceptor);
   http.addFilter(securityInterceptor);
   http.setSharedObject(FilterSecurityInterceptor.class, securityInterceptor);
}

可见,目的正是为了生成一个 FilterSecurityInterceptor 既 Filter 对象,并将其载入到 HttpSecurity 对象中;

FormLoginConfigurer

同样,该对象的 configure 方法也是在其父类 AbstractAuthenticationFilterConfigurer 中;

@Override
public void configure(B http) throws Exception {
   PortMapper portMapper = http.getSharedObject(PortMapper.class);
   if (portMapper != null) {
      authenticationEntryPoint.setPortMapper(portMapper);
   }

   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);
}

上面代码的核心在 authFilter,而该 authFilter 正是 UsernamePasswordAuthenticationFilter,该 authFilter 的初始化过程在 FormLoginConfigurer 的构造函数中,

public FormLoginConfigurer() {
   super(new UsernamePasswordAuthenticationFilter(), null);
   usernameParameter("username");
   passwordParameter("password");
}

UserDetailsAwareConfigurer

UserDetailsAwareConfigurer 主要涉及两个实体类 InMemoryUserDetailsManagerConfigurerJdbcUserDetailsManagerConfigurer ;顾名思义,这两个类都是对用户身份信息进行验证的类;如类图中所示,这两个 configurers 将会作为 AuthenticationManagerBuilder 的 configures 来进行构建,最终构建的结果是返回一个 ProviderManager 对象;有关这部分内容笔者将会在下一章节对其进行描述;

总结

正如对 WebSecurity 的总结 那样,WebSecurity 与 HttpSecurity 的关系是一对多的关系,也就是说,HttpSecurity 正是为 Spring Security 构建多个安全链 SecurityFilterChain 的核心类;WebSecurity 将构建出 FilterChainProxy, FilterChainProxy 包含多个 SecurityFilterChain 既安全链;


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

ACM国际大学生程序设计竞赛亚洲区预选赛真题题解

ACM国际大学生程序设计竞赛亚洲区预选赛真题题解

郭炜 / 电子工业 / 2011-7 / 49.00元

ACM国际大学生程序设计竞赛(ACM International Collegiate Programming Contest,简称ACM/ICPC)是世界上历史最悠久,规模最大、最具声望的程序设计竞赛,一直受到众多国际知名大学的重视,全球著名IT公司更是争相招募竞赛的优胜者。 该项赛事分为各大洲预选赛和全球总决赛两个阶段。北京大学多次在亚洲区预选赛中负责命题工作,是中国在ACM/ICPC命......一起来看看 《ACM国际大学生程序设计竞赛亚洲区预选赛真题题解》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具