SpringSecurity原理分析

  • Post author:
  • Post category:其他


距离上次更新已经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

在这里插入图片描述

​ 这里也就是说,先执行

Tomcat

自身已有的

Filter

,然后再交给

SpringSecurity

定义的

FilterChainProxy

,然后其再去执行

SpringSecurity

用于认证、授权管理的各种

Filter

。这个就是

SpringSecurity

的核心原理。



2、默认注入的Filter列表

​ 我们看下默认引入

spring-boot-starter-security

后其会默认加入的

Filter

在这里插入图片描述



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

,这两个类就是

WebSecurity



HttpSecurity



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

,与

sharedObjects



configurers(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<SecurityConfigurer)

,而我们当前有添加一个

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<O, B extends SecurityBuilder<O>>
      extends AbstractSecurityBuilder<O> {
		...........
   @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()

遍历执行

configurers



configurer

方法:

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

,以及属于

SpringSecurity



Filter`。



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

​ 这里你可以添加自己的

AuthenticationProvider



UserDetailsService

,或使用自带的内存UserDetailsService

inMemoryAuthentication()

,其是通过

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<AuthenticationManager, AuthenticationManagerBuilder>
		implements ProviderManagerBuilder<AuthenticationManagerBuilder> {
		..........
    @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));
}

在这里插入图片描述

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

中。

在这里插入图片描述

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

在这里插入图片描述

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

处理认证失败的情况。

在这里插入图片描述

在这里插入图片描述

​ 其就是通过

failureHandler

来跳到

/login?error

页面

在这里插入图片描述

然后对于

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)、对于认证的流程

在这里插入图片描述



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

在这里插入图片描述



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

​ 然后对于

applyDefaultConfiguration



http.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 {

在这里插入图片描述



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

在这里插入图片描述

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

,就直接返回

text



HttpStatus.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

在这里插入图片描述

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

的组装。



版权声明:本文为qq_25179481原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。