SpringSecurity原理分析

距离上次更新已经5个月了,因为这段时间主要是面试准备+适应新公司的内容,8月份离职,9月份入职,虽然看了很多内容,但没有进行系统整理。之后应该也会渐渐的整理一些内容,会继续更新,虽然没什么人看,但还是说明下,_O(∩_∩)O哈哈~。

​ 这一篇我们主要梳理下SpringSecurity的原理,SpringSecurity主要是用于认证、授权的,其的主要原理就是通过Filter来处理。

一、SpringSecurity的基本原理

1、基本流程

SpringSecurity的基本原理就是应用了Tomcat容器的Filter,其的实现原理也就是类似于Tomcat本身的ApplicationFilterChain,也就是Filter执行链。

public final class ApplicationFilterChain implements FilterChain {
    		........
    private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0];
	...........
    public ApplicationFilterChain() {
    }

    public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
       		..........
        } else {
            this.internalDoFilter(request, response);
        }

    }

    private void internalDoFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
        if (this.pos < this.n) {
            ApplicationFilterConfig filterConfig = this.filters[this.pos++];

            try {
                Filter filter = filterConfig.getFilter();
               		.........
                } else {
                    filter.doFilter(request, response, this);
                }
				.........
        } else {
            try {
               		.........
                } else {
                    this.servlet.service(request, response);
                }
            } ........

            }
        }
    }

ApplicationFilterChain本身就是先执行所有的filters,执行完成后,其就会执行当前请求的Servlet,对于SpringMVC来说,就是DispatchSevelt

SpringSecurity原理分析_第1张图片

​ 这里也就是说,先执行Tomcat自身已有的Filter,然后再交给SpringSecurity定义的FilterChainProxy,然后其再去执行SpringSecurity用于认证、授权管理的各种Filter。这个就是SpringSecurity的核心原理。

2、默认注入的Filter列表

​ 我们看下默认引入spring-boot-starter-security后其会默认加入的Filter

SpringSecurity原理分析_第2张图片

3、FilterChainProxy

public class FilterChainProxy extends GenericFilterBean {
		..........
   private void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain)
         throws IOException, ServletException {
     	......
      List<Filter> filters = getFilters(firewallRequest);
     		........
      VirtualFilterChain virtualFilterChain = new VirtualFilterChain(firewallRequest, chain, filters);
      virtualFilterChain.doFilter(firewallRequest, firewallResponse);
   }
	........

   private static final class VirtualFilterChain implements FilterChain {
      private final FilterChain originalChain;

      private final List<Filter> additionalFilters;
		..........
      @Override
      public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
         if (this.currentPosition == this.size) {
            if (logger.isDebugEnabled()) {
               logger.debug(LogMessage.of(() -> "Secured " + requestLine(this.firewalledRequest)));
            }
            // Deactivate path stripping as we exit the security filter chain
            this.firewalledRequest.reset();
            this.originalChain.doFilter(request, response);
            return;
         }
         this.currentPosition++;
         Filter nextFilter = this.additionalFilters.get(this.currentPosition - 1);
         if (logger.isTraceEnabled()) {
            logger.trace(LogMessage.format("Invoking %s (%d/%d)", nextFilter.getClass().getSimpleName(),
                  this.currentPosition, this.size));
         }
         nextFilter.doFilter(request, response, this);
      }

   }

二、SpringSecurity对FilterChain的组装初始化

​ 其的组装是借助于两个类来添加关于认证、授权相关的信息,由这些信息来添加FilterChain中需要的Filter,这两个类就是WebSecurityHttpSecurity

1、WebSecurity、HttpSecurity

​ 这两个类都是继承的AbstractConfiguredSecurityBuilder,以及实现SecurityBuilder接口(用于构建对象)。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6vdAJhTC-1638686018791)(F:\MarkDown-File\知识点资料\Untitled.assets\image-20211204221618377.png)]

public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter, WebSecurity>
      implements SecurityBuilder<Filter>, ApplicationContextAware {
public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain, HttpSecurity>
      implements SecurityBuilder<DefaultSecurityFilterChain>, HttpSecurityBuilder<HttpSecurity> {
public interface SecurityBuilder<O> {

   O build() throws Exception;

}

2、AbstractConfiguredSecurityBuilder

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

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

   private final Map<Class<?>, Object> sharedObjects = new HashMap<>();

​ 这个基类主要有两个成员变量需要关注,也就是configurers,与sharedObjectsconfigurers(SecurityConfigurer)这个主要是添加的各种配置信息。然后sharedObjects中是添加一些共享的类对象,然后需要就能取出来。例如:

private Map<Class<?>, Object> createSharedObjects() {
   Map<Class<?>, Object> sharedObjects = new HashMap<>();
   sharedObjects.putAll(this.localConfigureAuthenticationBldr.getSharedObjects());
   sharedObjects.put(UserDetailsService.class, userDetailsService());
   sharedObjects.put(ApplicationContext.class, this.context);
   sharedObjects.put(ContentNegotiationStrategy.class, this.contentNegotiationStrategy);
   sharedObjects.put(AuthenticationTrustResolver.class, this.trustResolver);
   return sharedObjects;
}

​ 而对于SecurityConfigurer的添加主要是使用apply()方法:

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

3、SecurityConfigurer

public interface SecurityConfigurer<O, B extends SecurityBuilder<O>> {

   void init(B builder) throws Exception;

   void configure(B builder) throws Exception;

}

​ 其主要是两个方法,一个就是先init产生化,另一个就是configure,也就是通过configure方法来设置SecurityBuilder中的内容。

下面我们来看下WebSecurity的构建,以及通过其来产生FilterChainProxy

@Autowired(required = false)
public void setFilterChainProxySecurityConfigurer(ObjectPostProcessor<Object> objectPostProcessor,
      @Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers)
      throws Exception {
   this.webSecurity = objectPostProcessor.postProcess(new WebSecurity(objectPostProcessor));
   if (this.debugEnabled != null) {
      this.webSecurity.debug(this.debugEnabled);
   }
  	..........
   for (SecurityConfigurer<Filter, WebSecurity> webSecurityConfigurer : webSecurityConfigurers) {
      this.webSecurity.apply(webSecurityConfigurer);
   }
   this.webSecurityConfigurers = webSecurityConfigurers;
}

​ 这里我们看到入参有webSecurityConfigurers(List,而我们当前有添加一个WebSecurityConfigurerAdapter, 其是继承与WebSecurityConfigurerAdapter,可以看到其是属于SecurityConfigurer,我们能通过其来进行对应的属性拓展

​ 然后就是通过this.webSecurity.apply(webSecurityConfigurer)来添加到configurers

4、构建Filter(FilterChainProxy)

@Configuration(proxyBeanMethods = false)
public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAware {

   private WebSecurity webSecurity;
		.....
    private List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers;

	private List<SecurityFilterChain> securityFilterChains = Collections.emptyList();
   @Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
   public Filter springSecurityFilterChain() throws Exception {
      	........
      return this.webSecurity.build();
   }
@Override
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 abstract class AbstractConfiguredSecurityBuilder>
      extends AbstractSecurityBuilder {
		...........
   @Override
   protected final O doBuild() throws Exception {
      synchronized (this.configurers) {
         this.buildState = BuildState.INITIALIZING;
         beforeInit();
         init();
         this.buildState = BuildState.CONFIGURING;
         beforeConfigure();
         configure();
         this.buildState = BuildState.BUILDING;
         O result = performBuild();
         this.buildState = BuildState.BUILT;
         return result;
      }
   }

​ 这里的init(),就是遍历configurers进行初始化:

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 : this.configurersAddedInInitializing) {
      configurer.init((B) this);
   }
}

再通过configure()遍历执行configurersconfigurer方法:

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

例如我们当前添加了自定义的SecurityConfiguration

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S5cLdHCB-1638686018792)(F:\MarkDown-File\知识点资料\Untitled.assets\image-20211204230515150.png)]

​ 这里还有beforeConfigure()方法,例如HttpSecurity对其的实现:

@Override
protected void beforeConfigure() throws Exception {
   setSharedObject(AuthenticationManager.class, getAuthenticationRegistry().build());
}

​ 添加认证管理器。对于SecurityConfigurer的实现类来说,其主要是设置填充各种类对象例如我们当前填充了``UserDetailsService,以及属于SpringSecurityFilter`。

5、HttpSecurity构建

​ 对于HttpSecurity的构建,其是在WebSecurity下构建的:

public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigurer<WebSecurity> {
		...........
   @Override
   public void init(WebSecurity web) throws Exception {
      HttpSecurity http = getHttp();
      web.addSecurityFilterChainBuilder(http).postBuildAction(() -> {
         FilterSecurityInterceptor securityInterceptor = http.getSharedObject(FilterSecurityInterceptor.class);
         web.securityInterceptor(securityInterceptor);
      });
   }

​ 我们看到其是在前面doBuild()遍历调用init调用的。创建后,通过web.addSecurityFilterChainBuilder(http)添加到WebSecurity中。而定义对于HttpSecurity,其主要会通过SecurityConfigurer来添加各种Filter

public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain, HttpSecurity>
      implements SecurityBuilder<DefaultSecurityFilterChain>, HttpSecurityBuilder<HttpSecurity> {

   private final RequestMatcherConfigurer requestMatcherConfigurer;

   private List<OrderedFilter> filters = new ArrayList<>();

   private RequestMatcher requestMatcher = AnyRequestMatcher.INSTANCE;

   private FilterOrderRegistration filterOrders = new FilterOrderRegistration();
protected final HttpSecurity getHttp() throws Exception {
   if (this.http != null) {
      return this.http;
   }
	........
   AuthenticationManager authenticationManager = authenticationManager();
   this.authenticationBuilder.parentAuthenticationManager(authenticationManager);
   Map<Class<?>, Object> sharedObjects = createSharedObjects();
   this.http = new HttpSecurity(this.objectPostProcessor, this.authenticationBuilder, sharedObjects);
   if (!this.disableDefaults) {
      applyDefaultConfiguration(this.http);
      ClassLoader classLoader = this.context.getClassLoader();
      List<AbstractHttpConfigurer> defaultHttpConfigurers = SpringFactoriesLoader
            .loadFactories(AbstractHttpConfigurer.class, classLoader);
      for (AbstractHttpConfigurer configurer : defaultHttpConfigurers) {
         this.http.apply(configurer);
      }
   }
   configure(this.http);
   return this.http;
}

​ 这里主要有三部:

1)、创建AuthenticationManager

AuthenticationManager authenticationManager = authenticationManager();

2)、再构建HttpSecurity

this.http = new HttpSecurity(this.objectPostProcessor, this.authenticationBuilder, sharedObjects);

3)、填充HttpSecurity的配置内容。

this.http.apply(configurer);

​ 我们下面再具体梳理这个过程。

6、AuthenticationManager

1)、AuthenticationManager认证管理器

protected AuthenticationManager authenticationManager() throws Exception {
   if (!this.authenticationManagerInitialized) {
      configure(this.localConfigureAuthenticationBldr);
     	........
      else {
         this.authenticationManager = this.localConfigureAuthenticationBldr.build();
      }
      this.authenticationManagerInitialized = true;
   }
   return this.authenticationManager;
}

​ 其首先会调用configure(AuthenticationManagerBuilder)

2)、AuthenticationManagerBuilder设置授权管理器的内容

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 InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder> inMemoryAuthentication()
			throws Exception {
		return apply(new InMemoryUserDetailsManagerConfigurer<>());
	}
    .........
    public <T extends UserDetailsService> DaoAuthenticationConfigurer<AuthenticationManagerBuilder, T> userDetailsService(
			T userDetailsService) throws Exception {
		this.defaultUserDetailsService = userDetailsService;
		return apply(new DaoAuthenticationConfigurer<>(userDetailsService));
	}
    .........
    @Override
	public AuthenticationManagerBuilder authenticationProvider(AuthenticationProvider authenticationProvider) {
		this.authenticationProviders.add(authenticationProvider);
		return this;
	}
    .......
    private <C extends UserDetailsAwareConfigurer<AuthenticationManagerBuilder, ? extends UserDetailsService>> C apply(
			C configurer) throws Exception {
		this.defaultUserDetailsService = configurer.getUserDetailsService();
		return super.apply(configurer);
	}
    

​ 这里你可以添加自己的AuthenticationProviderUserDetailsService,或使用自带的内存UserDetailsServiceinMemoryAuthentication(),其是通过SecurityConfigurer来添加HttpSecurity的属性。

例如我们当前的WebSecurityConfigurerAdapter

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-91ipl8lM-1638686018793)(F:\MarkDown-File\知识点资料\Untitled.assets\image-20211204224354651.png)]

public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

​ 其就设置UserDetailsService为我们自定义的。然后这里通过configure(AuthenticationManagerBuilder)拓展好AuthenticationManagerBuilder的一些属性后,下面就能通过来创建了。

3)、构建AuthenticationManager

localConfigureAuthenticationBldr.build()

这个build()同样是父类AbstractSecurityBuilder的方法:

@Override
protected final O doBuild() throws Exception {
   synchronized (this.configurers) {
      this.buildState = BuildState.INITIALIZING;
      beforeInit();
      init();
      this.buildState = BuildState.CONFIGURING;
      beforeConfigure();
      configure();
      this.buildState = BuildState.BUILDING;
      O result = performBuild();
      this.buildState = BuildState.BUILT;
      return result;
   }
}

​ 其也是这一串逻辑:

​ 这个也主要是SecurityConfigurer的方法调用,然后其的performBuild()方法

public class AuthenticationManagerBuilder
		extends AbstractConfiguredSecurityBuilder
		implements ProviderManagerBuilder {
		..........
    @Override
    protected ProviderManager performBuild() throws Exception {
       if (!isConfigured()) {
          this.logger.debug("No authenticationProviders and no parentAuthenticationManager defined. Returning null.");
          return null;
       }
       ProviderManager providerManager = new ProviderManager(this.authenticationProviders,
             this.parentAuthenticationManager);
       if (this.eraseCredentials != null) {
          providerManager.setEraseCredentialsAfterAuthentication(this.eraseCredentials);
       }
       if (this.eventPublisher != null) {
          providerManager.setAuthenticationEventPublisher(this.eventPublisher);
       }
       providerManager = postProcess(providerManager);
       return providerManager;
    }

​ 这里就讲其的authenticationProviders设置到ProviderManager, 也就是ProviderManager认证管理器,通过其的AuthenticationProvider也就是认证提供者来处理认证内容:

4)、ProviderManager认证处理管理器

public class ProviderManager implements AuthenticationManager, MessageSourceAware, InitializingBean {
   private AuthenticationEventPublisher eventPublisher = new NullEventPublisher();
   private List<AuthenticationProvider> providers = Collections.emptyList();
	.......
   private AuthenticationManager parent;
	..........
   public ProviderManager(List<AuthenticationProvider> providers, AuthenticationManager parent) {
      Assert.notNull(providers, "providers list cannot be null");
      this.providers = providers;
      this.parent = parent;
      checkState();
   }
	........
   @Override
   public Authentication authenticate(Authentication authentication) throws AuthenticationException {
      Class<? extends Authentication> toTest = authentication.getClass();
      AuthenticationException lastException = null;
      AuthenticationException parentException = null;
      Authentication result = null;
      Authentication parentResult = null;
      int currentPosition = 0;
      int size = this.providers.size();
      for (AuthenticationProvider provider : getProviders()) {
         if (!provider.supports(toTest)) {
            continue;
         }
        	.........
         try {
            result = provider.authenticate(authentication);
            if (result != null) {
               copyDetails(authentication, result);
               break;
            }
         }
         	........
      }
      if (result == null && this.parent != null) {
         // Allow the parent to try.
         try {
            parentResult = this.parent.authenticate(authentication);
            result = parentResult;
         }
        	........
         return result;
      }
			.........
      throw lastException;
   }

​ 我们看到这里是通过AuthenticationProvider来处理产生Authentication,也就是认证信息。

​ 而对于这里的AuthenticationProvider,一般是怎样添加的呢?对于AuthenticationManagerBuilder,当我们设置UserDetailsService的时候,其就会添加DaoAuthenticationConfigurer

public <T extends UserDetailsService> DaoAuthenticationConfigurer<AuthenticationManagerBuilder, T> userDetailsService(
      T userDetailsService) throws Exception {
   this.defaultUserDetailsService = userDetailsService;
   return apply(new DaoAuthenticationConfigurer<>(userDetailsService));
}

SpringSecurity原理分析_第3张图片

public abstract class AbstractDaoAuthenticationConfigurer<B extends ProviderManagerBuilder<B>, C extends AbstractDaoAuthenticationConfigurer<B, C, U>, U extends UserDetailsService>
      extends UserDetailsAwareConfigurer<B, U> {

   private DaoAuthenticationProvider provider = new DaoAuthenticationProvider();


   AbstractDaoAuthenticationConfigurer(U userDetailsService) {
      this.userDetailsService = userDetailsService;
      this.provider.setUserDetailsService(userDetailsService);
      if (userDetailsService instanceof UserDetailsPasswordService) {
         this.provider.setUserDetailsPasswordService((UserDetailsPasswordService) userDetailsService);
      }
   }
		.........
   @Override
   public void configure(B builder) throws Exception {
      this.provider = postProcess(this.provider);
      builder.authenticationProvider(this.provider);
   }

​ 其就会产生一个DaoAuthenticationProvider,同时在configure(B builder)方法的时候,就会将DaoAuthenticationProvider设置到ProviderManagerBuilder中。

SpringSecurity原理分析_第4张图片

public abstract class AbstractUserDetailsAuthenticationProvider
      implements AuthenticationProvider, InitializingBean, MessageSourceAware {

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

   protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();

   private UserCache userCache = new NullUserCache();

   private boolean forcePrincipalAsString = false;

   protected boolean hideUserNotFoundExceptions = true;

   private UserDetailsChecker preAuthenticationChecks = new DefaultPreAuthenticationChecks();

   private UserDetailsChecker postAuthenticationChecks = new DefaultPostAuthenticationChecks();

   private GrantedAuthoritiesMapper authoritiesMapper = new NullAuthoritiesMapper();

   protected abstract void additionalAuthenticationChecks(UserDetails userDetails,
         UsernamePasswordAuthenticationToken authentication) throws AuthenticationException;

   @Override
   public final void afterPropertiesSet() throws Exception {
      Assert.notNull(this.userCache, "A user cache must be set");
      Assert.notNull(this.messages, "A message source must be set");
      doAfterPropertiesSet();
   }

   @Override
   public Authentication authenticate(Authentication authentication) throws AuthenticationException {
      Assert.isInstanceOf(UsernamePasswordAuthenticationToken.class, authentication,
            () -> this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.onlySupports",
                  "Only UsernamePasswordAuthenticationToken is supported"));
      String username = determineUsername(authentication);
      boolean cacheWasUsed = true;
      UserDetails user = this.userCache.getUserFromCache(username);
      if (user == null) {
         cacheWasUsed = false;
         try {
            user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication);
         }
         catch (UsernameNotFoundException ex) {
          	.........
            throw new BadCredentialsException(this.messages
                  .getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
         }
      }
      try {
         this.preAuthenticationChecks.check(user);
         additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken) authentication);
      }
      catch (AuthenticationException ex) {
         if (!cacheWasUsed) {
            throw ex;
         }
         user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication);
         this.preAuthenticationChecks.check(user);
         additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken) authentication);
      }
			.........
      return createSuccessAuthentication(principalToReturn, authentication, user);
   }
    ..........
   protected void additionalAuthenticationChecks(UserDetails userDetails,
			UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
		if (authentication.getCredentials() == null) {
			throw new BadCredentialsException(this.messages
					.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
		}
		String presentedPassword = authentication.getCredentials().toString();
		if (!this.passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {
			throw new BadCredentialsException(this.messages
					.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
		}
	}
public class DaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
	..........
   private PasswordEncoder passwordEncoder;

   private volatile String userNotFoundEncodedPassword;

   private UserDetailsService userDetailsService;
	.........

   @Override
   protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)
         throws AuthenticationException {
      prepareTimingAttackProtection();
      try {
         UserDetails loadedUser = this.getUserDetailsService().loadUserByUsername(username);
         if (loadedUser == null) {
            throw new InternalAuthenticationServiceException(
                  "UserDetailsService returned null, which is an interface contract violation");
         }
         return loadedUser;
      }
      catch (UsernameNotFoundException ex) {
         mitigateAgainstTimingAttack(authentication);
         throw ex;
      }
      catch (InternalAuthenticationServiceException ex) {
         throw ex;
      }
      catch (Exception ex) {
         throw new InternalAuthenticationServiceException(ex.getMessage(), ex);
      }
   }

​ 这里首先是通过retrieveUser方法使用UserDetailsService来查询到对应的用户,如果查询不到就抛出UsernameNotFoundException,如果能查询到,就再来解析认证判断,例如用户是否被锁定,密码是否匹配等,如果失败,就抛出AuthenticationException认证失败。

this.preAuthenticationChecks.check(user);
additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken) authentication);
@Override
public void check(UserDetails user) {
   if (!user.isAccountNonLocked()) {
      throw new LockedException(
            this.messages.getMessage("AccountStatusUserDetailsChecker.locked", "User account is locked"));
   }
   if (!user.isEnabled()) {
      throw new DisabledException(
            this.messages.getMessage("AccountStatusUserDetailsChecker.disabled", "User is disabled"));
   }
   if (!user.isAccountNonExpired()) {
      throw new AccountExpiredException(
            this.messages.getMessage("AccountStatusUserDetailsChecker.expired", "User account has expired"));
   }
   if (!user.isCredentialsNonExpired()) {
      throw new CredentialsExpiredException(this.messages
            .getMessage("AccountStatusUserDetailsChecker.credentialsExpired", "User credentials have expired"));
   }
}

​ 而对于AuthenticationException,也就是认证失败,我们看到这个异常是在接口控制的,所以一定要处理。

public interface AuthenticationProvider {

   Authentication authenticate(Authentication authentication) throws AuthenticationException;

​ 拿我们常见的UsernamePasswordAuthenticationFilter,也就是账密登录的Filter

SpringSecurity原理分析_第5张图片

public abstract class AbstractAuthenticationProcessingFilter extends GenericFilterBean
		implements ApplicationEventPublisherAware, MessageSourceAware {
    	.............
	private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
          throws IOException, ServletException {
       if (!requiresAuthentication(request, response)) {
          chain.doFilter(request, response);
          return;
       }
       try {
          Authentication authenticationResult = attemptAuthentication(request, response);
          if (authenticationResult == null) {
             // return immediately as subclass has indicated that it hasn't completed
             return;
          }
          this.sessionStrategy.onAuthentication(authenticationResult, request, response);
          // Authentication success
          if (this.continueChainBeforeSuccessfulAuthentication) {
             chain.doFilter(request, response);
          }
          successfulAuthentication(request, response, chain, authenticationResult);
       }
       catch (InternalAuthenticationServiceException failed) {
          this.logger.error("An internal error occurred while trying to authenticate the user.", failed);
          unsuccessfulAuthentication(request, response, failed);
       }
       catch (AuthenticationException ex) {
          // Authentication failed
          unsuccessfulAuthentication(request, response, ex);
       }
    }
public class UsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
		........
   @Override
   public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
         throws AuthenticationException {
      	.........
      UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
      // Allow subclasses to set the "details" property
      setDetails(request, authRequest);
      return this.getAuthenticationManager().authenticate(authRequest);
   }

其认证失败后就会通过AuthenticationException异常,来调用unsuccessfulAuthentication处理认证失败的情况。

SpringSecurity原理分析_第6张图片

SpringSecurity原理分析_第7张图片

​ 其就是通过failureHandler来跳到/login?error页面

SpringSecurity原理分析_第8张图片

然后对于UsernamePasswordAuthenticationFilter来说,其后面就是DefaultLoginPageGeneratingFilter

在这里插入图片描述

其通过url,就会构建登录页面,然后直接就return了,就不会通过chain.doFilter(request, response)到下面的其他Filter以及Servlet了。

private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
      throws IOException, ServletException {
   boolean loginError = isErrorPage(request);
   boolean logoutSuccess = isLogoutSuccess(request);
   if (isLoginUrlRequest(request) || loginError || logoutSuccess) {
      String loginPageHtml = generateLoginPageHtml(request, loginError, logoutSuccess);
      response.setContentType("text/html;charset=UTF-8");
      response.setContentLength(loginPageHtml.getBytes(StandardCharsets.UTF_8).length);
      response.getWriter().write(loginPageHtml);
      return;
   }
   chain.doFilter(request, response);
}

5)、对于认证的流程

SpringSecurity原理分析_第9张图片

7、applyDefaultConfiguration(this.http)默认设置

​ 我们接走上面的创建HttpSecurity的步骤,来看下HttpSecurity中的Filter是怎样添加的:

protected final HttpSecurity getHttp() throws Exception {
   if (this.http != null) {
      return this.http;
   }
   AuthenticationEventPublisher eventPublisher = getAuthenticationEventPublisher();
   this.localConfigureAuthenticationBldr.authenticationEventPublisher(eventPublisher);
   AuthenticationManager authenticationManager = authenticationManager();
   this.authenticationBuilder.parentAuthenticationManager(authenticationManager);
   Map<Class<?>, Object> sharedObjects = createSharedObjects();
   this.http = new HttpSecurity(this.objectPostProcessor, this.authenticationBuilder, sharedObjects);
   if (!this.disableDefaults) {
      applyDefaultConfiguration(this.http);
      ClassLoader classLoader = this.context.getClassLoader();
      List<AbstractHttpConfigurer> defaultHttpConfigurers = SpringFactoriesLoader
            .loadFactories(AbstractHttpConfigurer.class, classLoader);
      for (AbstractHttpConfigurer configurer : defaultHttpConfigurers) {
         this.http.apply(configurer);
      }
   }
   configure(this.http);
   return this.http;
}

​ 其首先会通过applyDefaultConfiguration(this.http)方法添加一些默认的Filter

private void applyDefaultConfiguration(HttpSecurity http) throws Exception {
   http.csrf();
   http.addFilter(new WebAsyncManagerIntegrationFilter());
   http.exceptionHandling();
   http.headers();
   http.sessionManagement();
   http.securityContext();
   http.requestCache();
   http.anonymous();
   http.servletApi();
   http.apply(new DefaultLoginPageConfigurer<>());
   http.logout();
}

​ 这里的例如http.csrf()http.headers()这些方法,其内部一般是这种方式,也就是需要什么就对应的调用方法例如http.anonymous(),其就会添加SecurityConfigurer,再等待configure()方法的调用,来注入对应SecurityConfigurer.configure的内容

public AnonymousConfigurer<HttpSecurity> anonymous() throws Exception {
   return getOrApply(new AnonymousConfigurer<>());
}

SpringSecurity原理分析_第10张图片

1)、AnonymousConfigurer

​ 例如当前的AnonymousConfigurer

public final class AnonymousConfigurer<H extends HttpSecurityBuilder<H>>
      extends AbstractHttpConfigurer<AnonymousConfigurer<H>, H> {
		........
   private AuthenticationProvider authenticationProvider;

   private AnonymousAuthenticationFilter authenticationFilter;

   private Object principal = "anonymousUser";

   private List<GrantedAuthority> authorities = AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS");
   	.............
   @Override
   public void init(H http) {
      if (this.authenticationProvider == null) {
         this.authenticationProvider = new AnonymousAuthenticationProvider(getKey());
      }
      if (this.authenticationFilter == null) {
         this.authenticationFilter = new AnonymousAuthenticationFilter(getKey(), this.principal, this.authorities);
      }
      this.authenticationProvider = postProcess(this.authenticationProvider);
      http.authenticationProvider(this.authenticationProvider);
   }

​ 其init方法就会创建一个AnonymousAuthenticationFilter匿名Filter,以及一个AnonymousAuthenticationProvider,匿名认证提供者。然后在configure方法就会将authenticationFilter添加到HttpSecurity中:

@Override
public void configure(H http) {
   this.authenticationFilter.afterPropertiesSet();
   http.addFilter(this.authenticationFilter);
}

2)、LogoutConfigurer

​ 然后对于applyDefaultConfigurationhttp.logout(),其添加的就是LogoutConfigurer

public LogoutConfigurer<HttpSecurity> logout() throws Exception {
   return getOrApply(new LogoutConfigurer<>());
}

这个就构建添加了LogoutFilter

@Override
public void configure(H http) throws Exception {
   LogoutFilter logoutFilter = createLogoutFilter(http);
   http.addFilter(logoutFilter);
}

当然我们也可以自动拓展来设置我们自己的信息:

@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

SpringSecurity原理分析_第11张图片

3)、FilterSecurityInterceptor

​ 当然我们上面是认证相关的内容,但还有授权信息,例如我们自己的拓展授权信息:

 @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin();
//                .loginPage("/index") // 配置哪个 url 为登录页面
//                .loginProcessingUrl("/login") // 设置哪个是登录的 url。
//                .successForwardUrl("/success") // 登录成功之后跳转到哪个 url
//                .failureForwardUrl("/fail");// 登录失败之后跳转到哪个 url
        http.authorizeRequests()
                .antMatchers("/ui/**","/index") //表示配置请求路径
                .permitAll() // 指定 URL 无需保护。
                .anyRequest() // 其他请求
                .authenticated(); //需要认证
// 关闭 csrf
        http.csrf().disable();
    }

例如http.authorizeRequests(),这个是授权具体的哪个请求资源,其添加的就是ExpressionUrlAuthorizationConfigurer,也就是表达式授权配置:

public ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry authorizeRequests()
      throws Exception {
   ApplicationContext context = getContext();
   return getOrApply(new ExpressionUrlAuthorizationConfigurer<>(context)).getRegistry();
}

SpringSecurity原理分析_第12张图片

public abstract class AbstractInterceptUrlConfigurer<C extends AbstractInterceptUrlConfigurer<C, H>, H extends HttpSecurityBuilder<H>>
      extends AbstractHttpConfigurer<C, H> {
    .........
   @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 (this.filterSecurityInterceptorOncePerRequest != null) {
         securityInterceptor.setObserveOncePerRequest(this.filterSecurityInterceptorOncePerRequest);
      }
      securityInterceptor = postProcess(securityInterceptor);
      http.addFilter(securityInterceptor);
      http.setSharedObject(FilterSecurityInterceptor.class, securityInterceptor);
   }

其就是通过这些信息来构建FilterSecurityInterceptor

public class FilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {
		......
   @Override
   public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
         throws IOException, ServletException {
      invoke(new FilterInvocation(request, response, chain));
   }
    
    public void invoke(FilterInvocation filterInvocation) throws IOException, ServletException {
			..........
		InterceptorStatusToken token = super.beforeInvocation(filterInvocation);
		try {
			filterInvocation.getChain().doFilter(filterInvocation.getRequest(), filterInvocation.getResponse());
		}
		finally {
			super.finallyInvocation(token);
		}
		super.afterInvocation(token, null);
	}

FilterSecurityInterceptor其是放在整条Filter链的最后一个:

​ 其的处理主要是beforeInvocation(filterInvocation)方法:

protected InterceptorStatusToken beforeInvocation(Object object) {
 	...........
   Authentication authenticated = authenticateIfRequired();
   if (this.logger.isTraceEnabled()) {
      this.logger.trace(LogMessage.format("Authorizing %s with attributes %s", object, attributes));
   }
   // Attempt authorization
   attemptAuthorization(object, attributes, authenticated);
	..........
   return new InterceptorStatusToken(SecurityContextHolder.getContext(), false, attributes, object);

}

​ 通过authenticateIfRequired来解析认证,如果有需要的话

private Authentication authenticateIfRequired() {
   Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
   if (authentication.isAuthenticated() && !this.alwaysReauthenticate) {
      if (this.logger.isTraceEnabled()) {
         this.logger.trace(LogMessage.format("Did not re-authenticate %s before authorizing", authentication));
      }
      return authentication;
   }
   authentication = this.authenticationManager.authenticate(authentication);
	........
   SecurityContextHolder.getContext().setAuthentication(authentication);
   return authentication;
}

​ 可以看到其本身其也是调用的认证管理器:this.authenticationManager.authenticate(authentication)

认证成功后就是授权attemptAuthorization(object, attributes, authenticated),这个就是你自己配置的一些规则:

private void attemptAuthorization(Object object, Collection<ConfigAttribute> attributes,
      Authentication authenticated) {
   try {
      this.accessDecisionManager.decide(authenticated, object, attributes);
   }
   catch (AccessDeniedException ex) {
      if (this.logger.isTraceEnabled()) {
         this.logger.trace(LogMessage.format("Failed to authorize %s with attributes %s using %s", object,
               attributes, this.accessDecisionManager));
      }
      else if (this.logger.isDebugEnabled()) {
         this.logger.debug(LogMessage.format("Failed to authorize %s with attributes %s", object, attributes));
      }
      publishEvent(new AuthorizationFailureEvent(object, attributes, authenticated, ex));
      throw ex;
   }
}

​ 其实通过访问决策管理器处理this.accessDecisionManager.decide(authenticated, object, attributes),如果没有权限,就抛出AccessDeniedException。与这个FilterSecurityInterceptor相关的就是其前面的ExceptionTranslationFilter这个Filter是放在FilterSecurityInterceptor前面的,其是通过默认的applyDefaultConfiguration(HttpSecurity http) 添加的http.exceptionHandling()

4)、ExceptionTranslationFilter

public ExceptionHandlingConfigurer<HttpSecurity> exceptionHandling() throws Exception {
   return getOrApply(new ExceptionHandlingConfigurer<>());
}
public void configure(H http) {
   AuthenticationEntryPoint entryPoint = getAuthenticationEntryPoint(http);
   ExceptionTranslationFilter exceptionTranslationFilter = new ExceptionTranslationFilter(entryPoint,
         getRequestCache(http));
   AccessDeniedHandler deniedHandler = getAccessDeniedHandler(http);
   exceptionTranslationFilter.setAccessDeniedHandler(deniedHandler);
   exceptionTranslationFilter = postProcess(exceptionTranslationFilter);
   http.addFilter(exceptionTranslationFilter);
}

​ 它的处理主要是两个,一个是处理AuthenticationException认证失败,另一个是AccessDeniedException访问授权失败

private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
      throws IOException, ServletException {
   try {
      chain.doFilter(request, response);
   }
   catch (IOException ex) {
      throw ex;
   }
   catch (Exception ex) {
    	......
      handleSpringSecurityException(request, response, chain, securityException);
   }
}
private void handleSpringSecurityException(HttpServletRequest request, HttpServletResponse response,
      FilterChain chain, RuntimeException exception) throws IOException, ServletException {
   if (exception instanceof AuthenticationException) {
      handleAuthenticationException(request, response, chain, (AuthenticationException) exception);
   }
   else if (exception instanceof AccessDeniedException) {
      handleAccessDeniedException(request, response, chain, (AccessDeniedException) exception);
   }
}

​ 通过这两个来处理response返回内容,如果是认证失败

private void handleAuthenticationException(HttpServletRequest request, HttpServletResponse response,
      FilterChain chain, AuthenticationException exception) throws ServletException, IOException {
   sendStartAuthentication(request, response, chain, exception);
}
protected void sendStartAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
      AuthenticationException reason) throws ServletException, IOException {
   SecurityContextHolder.getContext().setAuthentication(null);
   this.requestCache.saveRequest(request, response);
   this.authenticationEntryPoint.commence(request, response, reason);
}

​ 通过authenticationEntryPoint来处理,我们以其实现Http403ForbiddenEntryPoint为例:

public class Http403ForbiddenEntryPoint implements AuthenticationEntryPoint {
   @Override
   public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException arg2)
         throws IOException {
      logger.debug("Pre-authenticated entry point called. Rejecting access");
      response.sendError(HttpServletResponse.SC_FORBIDDEN, "Access Denied");
   }

}
int SC_FORBIDDEN = 403;

​ 其就是对response输出403,访问拒绝。

如果是授权失败,其有两种如果当前Authentication是匿名认证,就调用sendStartAuthentication,也就是与前面的handleAuthenticationException一样:

private void handleAccessDeniedException(HttpServletRequest request, HttpServletResponse response,
      FilterChain chain, AccessDeniedException exception) throws ServletException, IOException {
   Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
   boolean isAnonymous = this.authenticationTrustResolver.isAnonymous(authentication);
   if (isAnonymous || this.authenticationTrustResolver.isRememberMe(authentication)) {
      sendStartAuthentication(request, response, chain,
            new InsufficientAuthenticationException(
                  this.messages.getMessage("ExceptionTranslationFilter.insufficientAuthentication",
                        "Full authentication is required to access this resource")));
   }
   else {
      this.accessDeniedHandler.handle(request, response, exception);
   }
}

​ 如果不是匿名,则是通过AccessDeniedHandler访问拒绝处理其来处理,例如AccessDeniedHandlerImpl

@Override
public void handle(HttpServletRequest request, HttpServletResponse response,
      AccessDeniedException accessDeniedException) throws IOException, ServletException {
   if (response.isCommitted()) {
      logger.trace("Did not write to response since already committed");
      return;
   }
   if (this.errorPage == null) {
      logger.debug("Responding with 403 status code");
      response.sendError(HttpStatus.FORBIDDEN.value(), HttpStatus.FORBIDDEN.getReasonPhrase());
      return;
   }
   // Put exception into request scope (perhaps of use to a view)
   request.setAttribute(WebAttributes.ACCESS_DENIED_403, accessDeniedException);
   // Set the 403 status code.
   response.setStatus(HttpStatus.FORBIDDEN.value());
   // forward to error page.
   if (logger.isDebugEnabled()) {
      logger.debug(LogMessage.format("Forwarding to %s with status code 403", this.errorPage));
   }
   request.getRequestDispatcher(this.errorPage).forward(request, response);
}

​ 也就是如果没有设置指定的errorPage,就直接返回textHttpStatus.FORBIDDEN

FORBIDDEN(403, Series.CLIENT_ERROR, "Forbidden"),

​ 如果有页面,就forword到errorPage

8、filter的顺序

​ 同时我们前面只介绍了Filter的添加http.addFilter,当这里还有添加顺序:

@Override
public void configure(H http) {
   this.authenticationFilter.afterPropertiesSet();
   http.addFilter(this.authenticationFilter);
}
@Override
public HttpSecurity addFilter(Filter filter) {
   Integer order = this.filterOrders.getOrder(filter.getClass());
   if (order == null) {
      throw new IllegalArgumentException("The Filter class " + filter.getClass().getName()
            + " does not have a registered order and cannot be added without a specified order. Consider using addFilterBefore or addFilterAfter instead.");
   }
   this.filters.add(new OrderedFilter(filter, order));
   return this;
}

​ 我们在添加一个Filter的时候,还需要指定整个Filter的位置

public HttpSecurity addFilterAt(Filter filter, Class<? extends Filter> atFilter) {
   return addFilterAtOffsetOf(filter, 0, atFilter);
}

​ 当前Security自带添加是使用addFilter(Filter filter)方法,在添加时实现会在filterOrders获取其的顺序来添加,其的初始化是:

final class FilterOrderRegistration {

   private static final int INITIAL_ORDER = 100;

   private static final int ORDER_STEP = 100;

   private final Map<String, Integer> filterToOrder = new HashMap<>();

   FilterOrderRegistration() {
      Step order = new Step(INITIAL_ORDER, ORDER_STEP);
      put(ChannelProcessingFilter.class, order.next());
      order.next(); // gh-8105
      put(WebAsyncManagerIntegrationFilter.class, order.next());
      put(SecurityContextPersistenceFilter.class, order.next());
      put(HeaderWriterFilter.class, order.next());
      put(CorsFilter.class, order.next());
      put(CsrfFilter.class, order.next());
      put(LogoutFilter.class, order.next());
  		..........
      put(ExceptionTranslationFilter.class, order.next());
      put(FilterSecurityInterceptor.class, order.next());
      put(AuthorizationFilter.class, order.next());
      put(SwitchUserFilter.class, order.next());
   }

​ 这里初始化的时候就已经定义好顺序了

void put(Class<? extends Filter> filter, int position) {
   String className = filter.getName();
   if (this.filterToOrder.containsKey(className)) {
      return;
   }
   this.filterToOrder.put(className, position);
}

三、SpringSecurity对FilterChain的组装构建

1、添加HttpSecurity到WebSecurity

@Override
public void init(WebSecurity web) throws Exception {
   HttpSecurity http = getHttp();
   web.addSecurityFilterChainBuilder(http).postBuildAction(() -> {
      FilterSecurityInterceptor securityInterceptor = http.getSharedObject(FilterSecurityInterceptor.class);
      web.securityInterceptor(securityInterceptor);
   });
}
public WebSecurity addSecurityFilterChainBuilder(
      SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder) {
   this.securityFilterChainBuilders.add(securityFilterChainBuilder);
   return this;
}

HttpSecurity构建好后,就讲其添加到WebSecurity中,继续构建WebSecurity

@Override
protected final O doBuild() throws Exception {
   synchronized (this.configurers) {
      this.buildState = BuildState.INITIALIZING;
      beforeInit();
      init();
      this.buildState = BuildState.CONFIGURING;
      beforeConfigure();
      configure();
      this.buildState = BuildState.BUILDING;
      O result = performBuild();
      this.buildState = BuildState.BUILT;
      return result;
   }
}

2、performBuild完成FilterChainProxy创建

@Override
protected Filter performBuild() throws Exception {
   int chainSize = this.ignoredRequests.size() + this.securityFilterChainBuilders.size();
   List<SecurityFilterChain> securityFilterChains = new ArrayList<>(chainSize);
   for (RequestMatcher ignoredRequest : this.ignoredRequests) {
      securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
   }
   for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : this.securityFilterChainBuilders) {
      securityFilterChains.add(securityFilterChainBuilder.build());
   }
   FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
   if (this.httpFirewall != null) {
      filterChainProxy.setFirewall(this.httpFirewall);
   }
   if (this.requestRejectedHandler != null) {
      filterChainProxy.setRequestRejectedHandler(this.requestRejectedHandler);
   }
   filterChainProxy.afterPropertiesSet();

   Filter result = filterChainProxy;
   this.postBuildAction.run();
   return result;
}

​ 这里的处理我们可以看到FilterChainProxy创建会通过(securityFilterChains),我们前面添加的HttpSecurity

SpringSecurity原理分析_第13张图片

public FilterChainProxy(List<SecurityFilterChain> filterChains) {
   this.filterChains = filterChains;
}

3、FilterChainProxy的拦截逻辑

这个逻辑前面贴过了

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
      throws IOException, ServletException {
    ........
      doFilterInternal(request, response, chain);
   	......
}

private void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain)
      throws IOException, ServletException {
 	...........
   List<Filter> filters = getFilters(firewallRequest);
	..........
   VirtualFilterChain virtualFilterChain = new VirtualFilterChain(firewallRequest, chain, filters);
   virtualFilterChain.doFilter(firewallRequest, firewallResponse);
}

private List<Filter> getFilters(HttpServletRequest request) {
   int count = 0;
   for (SecurityFilterChain chain : this.filterChains) {
      if (chain.matches(request)) {
         return chain.getFilters();
      }
   }
   return null;
}

​ 我们当前的是SecurityFilterChain是通过HttpSecurity构建的,通过doBuilder

public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain, HttpSecurity>
		implements SecurityBuilder<DefaultSecurityFilterChain>, HttpSecurityBuilder<HttpSecurity> {
    	......
    private List<OrderedFilter> filters = new ArrayList<>();
	private RequestMatcher requestMatcher = AnyRequestMatcher.INSTANCE;
    ...........
    @Override
    protected DefaultSecurityFilterChain performBuild() {
       this.filters.sort(OrderComparator.INSTANCE);
       List<Filter> sortedFilters = new ArrayList<>(this.filters.size());
       for (Filter filter : this.filters) {
          sortedFilters.add(((OrderedFilter) filter).filter);
       }
       return new DefaultSecurityFilterChain(this.requestMatcher, sortedFilters);
    }

​ 也就是将HttpSecurity以及其的匹配器RequestMatcher来构建。

public final class AnyRequestMatcher implements RequestMatcher {

   public static final RequestMatcher INSTANCE = new AnyRequestMatcher();

   private AnyRequestMatcher() {
   }

   @Override
   public boolean matches(HttpServletRequest request) {
      return true;
   }

​ 这个匹配器都拦截。

​ 由此就完成了FilterChain的组装。

你可能感兴趣的:(#,Spring系列,Java框架,java,SpringSecurity)