Spring Security过滤器链分析(spring security 过滤器)

  本篇文章为你整理了Spring Security过滤器链分析(spring security 过滤器)的详细内容,包含有spring security过滤器链原理 spring security 过滤器 springsecurity过滤器顺序 spring filter过滤器详细讲解 Spring Security过滤器链分析,希望能帮助你了解 Spring Security过滤器链分析。

  过滤器链分析

    提起Spring Security的实现原理,很多读者都会想到过滤器链。因为Spring Security中的所有功能都是通过过滤器来实现的,这些过滤器组成一个完整的过滤器链。那么,这些过滤器 链是如何初始化的?我们前面反复提到的AuthenticationManager又是如何初始化的?通过前面章节的学习,相信读者己经有了一些认识,本章我们将从头开始,分析Spring Security的初始化流程,同时再通过六个案例来让读者深入理解并且学会如何制作过滤器链。由于初始化流程相对复杂,因此我们没有选择在一开始就讲解Spring Security初始化流程,而是放到本节。当读者对于Spring Security有一个基本的认知之后再来讲解,此时相对来说就会比较容易理解。

  本章涉及的主要知识点有:

  初始化流程分析。

  ObjectPostProcessor 的使用。

  多种用户定义方式。

  定义多个过滤器链。

  静态资源过滤。

  使用JSON格式登录。

  添加登录验证码。

  1. 初始化流程分析

    Spring Security初始化流程整体上来说理解起来并不难,但是这里涉及许多零碎的知识点, 把这些零碎的知识点搞懂了,再来梳理初始化流程就会容易很多。因此,这里先介绍一下SpringSecurity中一些常见的关键组件,在理解这些组件的基础上,再来分析初始化流程,就能加深对其的理解。

    1.1ObjectPostProcessor  

    ObjectPostProcessor是Spring Security中使用频率最高的组件之一,它是一个对象后置处理器,也就是当一个对象创建成功后,如果还有一些额外的事情需要补充,那么可以通过 ObjectPostProcessor来进行处理。这个接口中默认只有一个方法postProcess,该方法用来完成对对象的二次处理,代码如下:

  

public interface ObjectPostProcessor T {

 

   O extends T O postProcess(O object);

  }

 

    ObjectPostProcessor默认有两个继承类,如图4-1所示。

  图 4-1

  AutowireBeanFactoryObjectPostProcessor:由于 Spring Security 中大量采用了 Java 配置, 许多过滤器都是直接new出来的,这些直接new出来的对象并不会自动注入到Spring 容器中。Spring Security这样做的本意是为了简化配置,但是却带来了另外一个问题就是, 大量new出来的对象需要我们手动注册到Spring客器中去。AutowireBeanFactoryObjectPostProcessor对象所承担的就是这件事,一个对象new出来之后,只要调用 AutowireBeanFactoryObjectPostProcessor.postProcess 方法,就可以成功注入到 Spring 容器中,它的实现原理就是通过调用Spring容器中的AutowireCapableBeanFactory对象将一个new出来的对象注入到Spring容器中去。

  CompositeObjectPostProcessor:这是ObjectPostProcessor 的另一个实现,一个对象可以有一个后置处理器,开发者也可以自定义多个对象后置处理器。 CompositeObjectPostProcessor是一个组合的对象后置处理器,它里边维护了一个List集合,集合中存放了某一个对象的所有后置处理器,当需要执行对象的后置处理器时,会遍历集合中的所有ObjectPostProcessor实例,分别调用实例的postProcess方法进行对象后置处理。在Spring Security框架中,最终使用的对象后置处理器其实就是 CompositeObjectPostProcessor ,它里边的集合默认只有一个对象,就是 AutowireBeanFactoryObjectPostProcessor。

    在Spring Security中,开发者可以灵活地配置项目中需要哪些Spring Security过滤器,一 旦选定过滤器之后,每一个过滤器都会有一个对应的配置器,叫作xxxConfigurer (例如CorsConfigurer. CsrfConfigurer等),过滤器都是在 xxxConfigurer 中 new 出来的,然后在 postProcess方法中处理一遍,就将这些过滤器注入到Spring容器中了。这是对象后置处理器ObjectPostProcessor的主要作用。

    1.2 SecurityFilterChain

    从名称上可以看出,SecurityFilterChain就是Spring Security中的过滤器链对象。下面来看一下 SecurityFilterChain的源码:

  

public interface SecurityFilterChain {

 

   boolean matches(HttpServletRequest request);

   List Filter getFilters();

  }

 

  可以看到,SecurityFilterChain中有两个方法:

  matches:该方法用来判断request请求是否应该被当前过滤器链所处理心

  getFilters:该方法返回一个List集合,集合中存放的就是Spring Security中的过滤器。换言之,如果matches方法返回true,那么request请求就会在getFilters方法所返回的Filter 集合中被处理。

  SecurityFilterChain只有一个默认的实现类就是DefaultSecurityFilterChain,其中定义了两 个属性,并具体实现了 SecurityFilterChain中的两个方法:

  

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的构造方法中,需要传入两个对象,一个是请求 匹配器requestMatcher,另一个则是过滤器集合或者过滤器数组filters。这个实现类比较简单, 这里就不再赘述了。

    需要注意的是,在一个Spring Security项目中,SecurityFilterChain的实例可能会有多个,在后面的小节中会详细分析,并演示多个SecurityFilterChain实例的情况。

    1.3SecurityBuilder

    Spring Security中所有需要构建的对象都可以通过SecurityBuilder来实现,默认的过滤器 链、代理过滤器AuthenticationManager 等,都可以通过 SecurityBuilder来构建。SecurityBuilder的实现类如图4-2所示。

  图 4-2

    SecurityBuilder:

    我们先来看SecurityBuilder的源码:

  

public interface SecurityBuilder O {

 

   O build() throws Exception;

  }

 

    由上述代码可以看到,SecurityBuilder中只有一个build方法,就是对象构建方法。build 方法的返回值,就是具体构建的对象泛型O,也就是说不同的SecurityBuilder将来会构建出不同的对象。

    HttpSecurityBuiIder:

    HttpSecurityBuilder是用来构建 HttpSecurity对象的,HttpSecurityBuilder 的定义如下:

  

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

  }

 

  我们简单分析一下这段源码:

  HttpSecurityBuilder对象本身在定义时就有一个泛型,这个泛型是HttpSecurityBuilder 的子类,由于默认情况下HttpSecurityBuilder的实现类只有一个HttpSecurity,所以可以暂且把接口中的H都当成HttpSecurity来理解。

  HttpSecurityBuilder 继承自 SecurityBuilder 接口,同时也指定了 SecurityBuilder 中的泛型为DefaultSecurityFilterChain,也就是说,HttpSecurityBuilder最终想要构建的对象是 DefaultSecurityFilterChain。

  getConfigurer方法用来获取一个配置器,所谓的配置器就是xxxConfigurer,我们将在下一小节中详细介绍配置器,

  removeConfigurer方法用来移除一个配置器(相当于从Spring Security过滤器链中移 除一个过滤器)。

  setSharedObject/getSharedObject这两个方法用来设置或者获取一个可以在多个配置器之间共享的对象。

  authenticationProvider 方法可以用来配置一个认证器 AuthenticationProvider。

  userDetailsService 方法可以用来配置一个数据源 UserDetailsService。

  addFilterAfter/addFilterBefore方法表示在某一个过滤器之后或者之前添加一个自定义的过滤器。

  addFilter方法可以添加一个过滤器,这个过滤器必须是Spring Security框架提供的 过滤器的一个实例或者其扩展,添加完成后,会自动进行过滤器的排序。

  AbstractSecurityBuilder:

    AbstractSecurityBuilder实现了 SecurityBuilder 接口,并对 build 做了完善,确保只 build 一次。我们来看—下 AbstractSecurityBuilder 源码:

  

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;

  }

 

  由上述代码可以看到,在AbstractSecurityBuilder类中:

  首先声明了 building变量,可以确保即使在多线程环境下,配置类也只构建一次。

  对build方法进行重写,并II设置为final,这样在AbstractSecurityBuilder的了类中 将不能再次重写build方法,在build方法内部,通过building变量来控制配置类只构建一次, 具体的构建工作则交给doBuild方法去完成。

  getObject方法用来返回构建的对象。

  doBuild方法则是具体的构建方法,该方法在AbstractSecurityBuilder中是一个抽象方法,具体的实现在其子类中。

  一言以蔽之,AbstractSecurityBuilder的作用是确保目标对象只被构建一次。

    AbstractConfiguredSecurityBuilder:

    AbstractConfiguredSecurityBuilder类的源码就稍微长一点,我们分别来看,首先在AbstractConfiguredSecurityBuilder中声明了一个枚举类,用来描述构建过程的不同状态:

  

private static 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:构建完成。

  这个枚举类里边还提供了两个判断方法 islnitializing 表示是否正在初始化中, isConfigured 方法表示是否已完成配置。

  AbstractConfiguredSecurityBuilder中还声明了 configurers变量,用来保存所有的配置类。针对configurers变量,我们可以进行添加配置、移除配置等操作,相关方法如下:

  

public abstract class AbstractConfiguredSecurityBuilder O, B extends SecurityBuilder O 

 

   extends AbstractSecurityBuilder O {

   private final Log logger = LogFactory.getLog(getClass());

   private final LinkedHashMap Class ? extends SecurityConfigurer O, B , List SecurityConfigurer O, B configurers = new LinkedHashMap Class ? extends SecurityConfigurer O, B , List SecurityConfigurer O, B

   private final List SecurityConfigurer O, B configurersAddedInInitializing = new ArrayList SecurityConfigurer O, B ();

   private final Map Class ? extends Object , Object sharedObjects = new HashMap Class ? extends Object , Object

   private final boolean allowConfigurersOfSameType;

   private BuildState buildState = BuildState.UNBUILT;

   private ObjectPostProcessor Object objectPostProcessor;

   protected AbstractConfiguredSecurityBuilder(

   ObjectPostProcessor Object objectPostProcessor) {

   this(objectPostProcessor, false);

   protected AbstractConfiguredSecurityBuilder(

   ObjectPostProcessor Object objectPostProcessor,

   boolean allowConfigurersOfSameType) {

   Assert.notNull(objectPostProcessor, "objectPostProcessor cannot be null");

   this.objectPostProcessor = objectPostProcessor;

   this.allowConfigurersOfSameType = allowConfigurersOfSameType;

   public O getOrBuild() {

   if (isUnbuilt()) {

   try {

   return build();

   catch (Exception e) {

   logger.debug("Failed to perform build. Returning null", e);

   return null;

   else {

   return getObject();

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

   @SuppressWarnings("unchecked")

   public C void setSharedObject(Class C sharedType, C object) {

   this.sharedObjects.put(sharedType, object);

   @SuppressWarnings("unchecked")

   public C C getSharedObject(Class C sharedType) {

   return (C) this.sharedObjects.get(sharedType);

   public Map Class ? extends Object , Object getSharedObjects() {

   return Collections.unmodifiableMap(this.sharedObjects);

   @SuppressWarnings("unchecked")

   private C extends SecurityConfigurer O, B void add(C configurer) throws Exception {

   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 SecurityConfigurer O, B (1);

   configs.add(configurer);

   this.configurers.put(clazz, configs);

   if (buildState.isInitializing()) {

   this.configurersAddedInInitializing.add(configurer);

   @SuppressWarnings("unchecked")

   public C extends SecurityConfigurer O, B List C getConfigurers(Class C clazz) {

   List C configs = (List C ) this.configurers.get(clazz);

   if (configs == null) {

   return new ArrayList ();

   return new ArrayList (configs);

   @SuppressWarnings("unchecked")

   public C extends SecurityConfigurer O, B List C removeConfigurers(Class C clazz) {

   List C configs = (List C ) this.configurers.remove(clazz);

   if (configs == null) {

   return new ArrayList ();

   return new ArrayList (configs);

   @SuppressWarnings("unchecked")

   public C extends SecurityConfigurer O, B C getConfigurer(Class C clazz) {

   List SecurityConfigurer O, B configs = this.configurers.get(clazz);

   if (configs == null) {

   return null;

   if (configs.size() != 1) {

   throw new IllegalStateException("Only one configurer expected for type "

   + clazz + ", but got " + configs);

   return (C) configs.get(0);

   @SuppressWarnings("unchecked")

   public C extends SecurityConfigurer O, B C removeConfigurer(Class C clazz) {

   List SecurityConfigurer O, B configs = this.configurers.remove(clazz);

   if (configs == null) {

   return null;

   if (configs.size() != 1) {

   throw new IllegalStateException("Only one configurer expected for type "

   + clazz + ", but got " + configs);

   return (C) configs.get(0);

   @SuppressWarnings("unchecked")

   public O objectPostProcessor(ObjectPostProcessor Object objectPostProcessor) {

   Assert.notNull(objectPostProcessor, "objectPostProcessor cannot be null");

   this.objectPostProcessor = objectPostProcessor;

   return (O) this;

   protected P P postProcess(P object) {

   return this.objectPostProcessor.postProcess(object);

  }

 

  我们解析一下这段源码:

  首先声明了一个configurers变量,用来保存所有的配置类,key是配置类Class对象, 值是一个List集合中放着配置类。

  apply方法有两个,参数类型略有差异,主要功能基本一致,都是向configurers变量中添加配置类,具体的添加过程则是调用add方法。

  add方法用来将所有的配置类保存到configurers中,在添加的过程中,如果 allowConfigurersOfSameType变量为true,则表示允许相同类型的配置类存在,也就是List集合中可以存在多个相同类型的配置类。默认情况下,如果是普通配置类, allowConfigurersOfSameType是false,所以List集合中的配置类始终只有一个配置类;如果在 AuthenticationManagerBuilder 中设置 allowConfigurersOfSameType 为 true,此时相同类型的配置类可以有多个(下文会详细分析AuthenticationManagerBuilder)。

  getConfigurers(Class C )方法可以从configurers中返回某一个配置类对应的所有实例

  removeConfigurers方法可以从configurers中移除某一个配置类对应的所有实例,并返回被移除掉的配置类实例集合,

  getConfigurer方法也是获取配置类实例,但是只获取集合中第一项。

  removeConfigurer方法可以从configurers中移除某一个配置类对应的所有配置类实例,并返回被移除掉的配置类实例中的第一项。

  getConfigurers方法是一个私有方法,主要是把所有的配置类实例放到一个集合中返 回.在配置类初始化和配置的时候,会调用到该方法,

  这些就是 AbstractConfiguredSecurityBuilder 中关于 configurers 的所有操作。

  接下来就是AbstractConfiguredSecurityBuilder中的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;

  protected void beforeInit() throws Exception {

  protected void beforeConfigure() throws Exception {

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

  private Collection SecurityConfigurer O, B getConfigurers() {

   List SecurityConfigurer O, B result = new ArrayList SecurityConfigurer O, B ();

   for (List SecurityConfigurer O, B configs : this.configurers.values()) {

   result.addAll(configs);

   return result;

  private boolean isUnbuilt() {

   synchronized (configurers) {

   return buildState == BuildState.UNBUILT;

  }

 

  
在doBuild方法中,一边更新构建状态,一边执行构建方法由构建方法中,beforeInit 是一个空的初始化方法,如果需要在初始化之前做一些准备工作,可以通过重写该方法实现,

  init方法是所有配置类的初始化方法,在该方法中,遍历所有的配置类,并调用其 init方法完成初始化操作。

  beforeConfigure方法可以在configure方法执行之前做一些准备操作心该方法默认也是一个空方法,

  configure方法用来完成所有配置类的配置,在configure方法中,遍历所有的配置类,分别调用其configure方法完成配置。

  performBuild方法用来做最终的构建操作,前面的准备工作完成后,最后在 performBuild方法中完成构建,这是一个抽象方法,具体的实现则在不同的配置类中。

  这些就是AbstractConfiguredSecurityBuilder中最主要的几个方法,其他一些方法比较简单,这里就不一一赘述了

  
ProviderManagerBuilder:

    ProviderManagerBuilder继承自 SecurityBuilder接口,并制定了构建的对象是 AuthenticationManager, 代码如下:

  

public interface ProviderManagerBuilder B extends ProviderManagerBuilder B extends

 

   SecurityBuilder AuthenticationManager {

   B authenticationProvider(AuthenticationProvider authenticationProvider);

  }

 

    可以看到,ProviderManagerBuilder 中增加 了一个 authenticationProvider 方法,同时通过泛型指定了构建的对象为AuthenticationManager。

  AuthenticationManagerBuilder:

    AuthenticationManagerBuilder 用来构建 AuthenticationManager 对象,它继承自 AbstractConfiguredSecurityBuilder,并且实现了 ProviderManagerBuilder接口,源码比较长,我们截取部分常用代码,代码如下:

  

public class AuthenticationManagerBuilder

 

   extends

   AbstractConfiguredSecurityBuilder AuthenticationManager, AuthenticationManagerBuilder

   implements ProviderManagerBuilder AuthenticationManagerBuilder {

   private final Log logger = LogFactory.getLog(getClass());

   private AuthenticationManager parentAuthenticationManager;

   private List AuthenticationProvider authenticationProviders = new ArrayList ();

   private UserDetailsService defaultUserDetailsService;

   private Boolean eraseCredentials;

   private AuthenticationEventPublisher eventPublisher;

   public AuthenticationManagerBuilder(ObjectPostProcessor Object objectPostProcessor) {

   super(objectPostProcessor, true);

   public AuthenticationManagerBuilder parentAuthenticationManager(

   AuthenticationManager authenticationManager) {

   if (authenticationManager instanceof ProviderManager) {

   eraseCredentials(((ProviderManager) authenticationManager)

   .isEraseCredentialsAfterAuthentication());

   this.parentAuthenticationManager = authenticationManager;

   return this;

   public AuthenticationManagerBuilder authenticationEventPublisher(

   AuthenticationEventPublisher eventPublisher) {

   Assert.notNull(eventPublisher, "AuthenticationEventPublisher cannot be null");

   this.eventPublisher = eventPublisher;

   return this;

   public AuthenticationManagerBuilder eraseCredentials(boolean eraseCredentials) {

   this.eraseCredentials = eraseCredentials;

   return this;

   public InMemoryUserDetailsManagerConfigurer AuthenticationManagerBuilder inMemoryAuthentication()

   throws Exception {

   return apply(new InMemoryUserDetailsManagerConfigurer ());

   public JdbcUserDetailsManagerConfigurer AuthenticationManagerBuilder jdbcAuthentication()

   throws Exception {

   return apply(new JdbcUserDetailsManagerConfigurer ());

   public T extends UserDetailsService DaoAuthenticationConfigurer AuthenticationManagerBuilder, T userDetailsService(

   T userDetailsService) throws Exception {

   this.defaultUserDetailsService = userDetailsService;

   return apply(new DaoAuthenticationConfigurer (

   userDetailsService));

   public LdapAuthenticationProviderConfigurer AuthenticationManagerBuilder ldapAuthentication()

   throws Exception {

   return apply(new LdapAuthenticationProviderConfigurer ());

   public AuthenticationManagerBuilder authenticationProvider(

   AuthenticationProvider authenticationProvider) {

   this.authenticationProviders.add(authenticationProvider);

   return this;

   @Override

   protected ProviderManager performBuild() throws Exception {

   if (!isConfigured()) {

   logger.debug("No authenticationProviders and no parentAuthenticationManager defined. Returning null.");

   return null;

   ProviderManager providerManager = new ProviderManager(authenticationProviders,

   parentAuthenticationManager);

   if (eraseCredentials != null) {

   providerManager.setEraseCredentialsAfterAuthentication(eraseCredentials);

   if (eventPublisher != null) {

   providerManager.setAuthenticationEventPublisher(eventPublisher);

   providerManager = postProcess(providerManager);

   return providerManager;

   public boolean isConfigured() {

   return !authenticationProviders.isEmpty() parentAuthenticationManager != null;

   public UserDetailsService getDefaultUserDetailsService() {

   return this.defaultUserDetailsService;

   private C extends UserDetailsAwareConfigurer AuthenticationManagerBuilder, ? extends UserDetailsService C apply(

   C configurer) throws Exception {

   this.defaultUserDetailsService = configurer.getUserDetailsService();

   return (C) super.apply(configurer);

  }

 

  
首先在AuthenticationManagerBuilder的构造方法中,调用了父类的构造方法,注意第二个参数传递了true,表示允许相同类型的配置类同时存在(结合 AbstractConfiguredSecurityBuilder 的源码来理解)

  parentAuthenticationManager 方法用来给一个 AuthenticationManager 设置 parents

  inMemoryAuthentication方法用来配置基于内存的数据源,该方法会自动创建 InMemoryUserDetailsManagerConfigurer配置类,并最终将该配置类添加到父类的configurers 变量中。由于设置了允许相同类型的配置类同时存在,因此inMemoryAuthentication方法可以反复调用多次

  jdbcAuthentication 以及 userDetailsService 方法与 inMemoryAuthentication 方法类似, 也是用来配置数据源的,这里不再赘述。

  authenticationProvider 方法用来向 authenticationProviders 集合中添加 AuthenticationProvider对象,根据前面第3节的介绍,我们己经知道一个AuthenticationManager实例中包含多个 AuthenticationProvider 实例,那么多个 AuthenticationProvider 实例可以通过 authenticationProvider方法进行添加。

  performBuild方法则执行具体的构建工作,常用的AuthenticationManager实例就是 ProviderManager,所以这里创建 ProviderManager 对象,并旦配置 authenticationProviders 和 parentAuthenticationManager对象,ProviderManager对象创建成功之后,再去对象后置处理器中处理一遍再返回。

  这就是AuthenticationManagerBuilder中的一个大致逻辑。

  HttpSecurity:

    HttpSecurity的主要作用是用来构建一条过滤器链,并反映到代码上,也就是构建一个 DefaultSecurityFilterChain 对象,一个 DefaultSecurityFilterChain 对象包含一个路径匹配器和多个Spring Security 过滤器,HttpSecurity 中通过收集各种各样的 xxxConfigurer,将 Spring Security 过滤器对应的配置类收集起来,并保存到父类AbstractConfiguredSecurityBuilder的configurers 变量中,在后续的构建过程中,再将这些xxxConfigurer构建为具体的Spring Security过滤器, 同时添加到HttpSecurity的filters对象中。

    由于HttpSecurity中存在大量功能类似的方法,因此这里挑选一个作为例子用来说明HttpSecurity的配置原。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: