SpringSecurity原理分析

Posted _微风轻起

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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

​ 这里也就是说,先执行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,这两个类就是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<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()遍历执行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.parentAuthenticationMan

以上是关于SpringSecurity原理分析的主要内容,如果未能解决你的问题,请参考以下文章

SpringSecurity原理分析

SpringSecurity原理分析

SpringSecurity原理分析

[SpringSecurity]web权限方案_自动登陆_原理分析和具体实现

JAVA——springSecurity——底层原理分析:处理认证请求和非认证请求的流程,主要过滤器链的作用

JAVA——springSecurity——底层原理分析:处理认证请求和非认证请求的流程,主要过滤器链的作用