默认SpringSecurity大致启动流程源码分析

默认SpringSecurity大致启动流程源码分析

了解基本流程

先了解spring.factories

spring.factories

org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration,\
  1. SecurityAutoConfiguration是主配置类,我们主要讲解该类
  2. UserDetailsServiceAutoConfiguration是用于设置默认密码的,它这将会在SecurityAutoConfiguration配置HttpSecurity时配置,所以我们不细讲
  3. SecurityFilterAutoConfiguration不讲
  4. 后面两个为OAuth安全,不讲

我们主要分析SecurityAutoConfiguration,它是一个自动配置类,受EnableWebSecurit 的影响,会加载前会先导入HttpSecurityConfigurationWebSecurityConfiguration

它们作用顺序分别为: HttpSecurityConfiguration配置HttpSecurityConfigurationWebSecurityConfiguration配置WebSecurity

流程主要也是围绕: 配置HttpSecurity --> 配置默认的基本的SecurityFilterChain --> 配置WebSecurity --> 配置最终的SecurityFilterChain

也可以理解为:如何创建最终的SecurityFilterChain呢 ?

EnableWebSecurity和EnableGlobalAuthentication注解

@Import({
    
     WebSecurityConfiguration.class, SpringWebMvcImportSelector.class, OAuth2ImportSelector.class,
      HttpSecurityConfiguration.class })
@EnableGlobalAuthentication
@Configuration
public @interface EnableWebSecurity {
    
    }
@Import(AuthenticationConfiguration.class)
@Configuration
public @interface EnableGlobalAuthentication {
    
    }

配置HttpSecurity

HttpSecurityConfiguration开始,该类是HttpSecurity的基本配置类,配置如下:

HttpSecurityConfiguration.java

@Autowired
void setAuthenticationConfiguration(AuthenticationConfiguration authenticationConfiguration) {
    
    
    this.authenticationConfiguration = authenticationConfiguration;
}//1
@Bean(HTTPSECURITY_BEAN_NAME)
@Scope("prototype")
HttpSecurity httpSecurity() throws Exception {
    
    
   WebSecurityConfigurerAdapter.LazyPasswordEncoder passwordEncoder = new WebSecurityConfigurerAdapter.LazyPasswordEncoder(
         this.context);//2
   AuthenticationManagerBuilder authenticationBuilder = new WebSecurityConfigurerAdapter.DefaultPasswordEncoderAuthenticationManagerBuilder(
         this.objectPostProcessor, passwordEncoder);//3
   authenticationBuilder.parentAuthenticationManager(authenticationManager());//4
   HttpSecurity http = new HttpSecurity(this.objectPostProcessor, authenticationBuilder, createSharedObjects());//5
   http
      .csrf(withDefaults())
      .addFilter(new WebAsyncManagerIntegrationFilter())
      .exceptionHandling(withDefaults())
      .headers(withDefaults())
      .sessionManagement(withDefaults())
      .securityContext(withDefaults())
      .requestCache(withDefaults())
      .anonymous(withDefaults())
      .servletApi(withDefaults())
      .apply(new DefaultLoginPageConfigurer<>());
   http.logout(withDefaults());//6
   return http;
}
  1. 依赖注入一个AuthenticationConfiguration,提前加载前面需要自动配置的AuthenticationConfiguration,

    该类创建了三个重要的Bean对象AuthenticationManagerBuild、InitializeUserDetailsBeanManagerConfigurer也就是和InitializeAuthenticationProviderBeanManagerConfigurer

    分别用来

    • 构建AuthenticationManager
    • 用来初始化spring.factories中的UserDetailsServiceAutoConfiguration,它的功能是提供默认的用户名和密码、
    • 初始化用户认证管理器(ProviderManager)
  2. 创建一个懒密码加载器

  3. 创建一个认证管理器构建器

  4. 构建一个认证管理器

    AuthenticationConfiguration.java

    public AuthenticationManager getAuthenticationManager() throws Exception {
           
           
       //...
       for (GlobalAuthenticationConfigurerAdapter config : this.globalAuthConfigurers) {
           
           
          authBuilder.apply(config);
       }//1
       this.authenticationManager = authBuilder.build();//2
       //...
       return this.authenticationManager;
    }
    
    1. 构建器使用全局认证配置,也就是前面创建AuthencationConfiguration时提及的

    2. 构建认证管理器

      直接看最后的doBuild()

      AbstractConfiguredSecurityBuilder

      protected final O doBuild() throws Exception {
                
                
         synchronized (this.configurers) {
                
                
            this.buildState = BuildState.INITIALIZING;
            beforeInit();//1
            init();//2
            this.buildState = BuildState.CONFIGURING;
            beforeConfigure();//3
            configure();//4
            this.buildState = BuildState.BUILDING;
            O result = performBuild();//5
            this.buildState = BuildState.BUILT;
            return result;
         }
      }
      
      1. 初始化前操作

      2. 初始化配置器

      3. 配置前操作

      4. 配置配置器,配置器有很多就不多讲了,配置过程如下:

        AbstractConfiguredSecurityBuilder

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

        该方法创建并返回PrivideManager

        AuthenticationManagerBuilder.java

        protected ProviderManager performBuild() throws Exception {
                     
                     
           ProviderManager providerManager = new ProviderManager(this.authenticationProviders,
                 this.parentAuthenticationManager);
           return providerManager;
        }
        
  5. 创建HttpSecurity,将之前的Privider注入HttpSecurity

  6. HttpSecurity配置基本的配置器


配置SecurityFilterChain

默认的HttpSecurity配置完之后,将会开始配置默认的SecurityFilterChain

我们看SecurityAutoConfiguration导入的SpringBootWebSecurityConfiguration

SpringBootWebSecurityConfiguration.java

@Configuration(proxyBeanMethods = false)
@ConditionalOnDefaultWebSecurity//1
@ConditionalOnWebApplication(type = Type.SERVLET)
class SpringBootWebSecurityConfiguration {
    
    
   @Bean
   @Order(SecurityProperties.BASIC_AUTH_ORDER)
   SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
    
    
      http.authorizeRequests().anyRequest().authenticated().and().formLogin().and().httpBasic();
      return http.build();//2
   }

}
  1. 该类在满足默认WebSecurity时才会配置,如下:

    @Conditional(DefaultWebSecurityCondition.class)//1
    public @interface ConditionalOnDefaultWebSecurity {
           
           }
    class DefaultWebSecurityCondition extends AllNestedConditions {
           
           
    	DefaultWebSecurityCondition() {
           
           super(ConfigurationPhase.REGISTER_BEAN);}
    	@ConditionalOnClass({
           
            SecurityFilterChain.class, HttpSecurity.class })
    	static class Classes {
           
           }//2
    	@ConditionalOnMissingBean({
           
            WebSecurityConfigurerAdapter.class, SecurityFilterChain.class })
    	static class Beans {
           
           }//3
    }
    
    
    1. 满足DefaultWebSecurityCondition条件
    2. 满足具有SecurityFilterChain.class, HttpSecurity.class两个类
    3. 满足缺少WebSecurityConfigurerAdapter.class, SecurityFilterChain.class两个Bean,,而默认的Security配置是缺少这两个类的
  2. 创建默认基本的SecurityFilterChain,这里创建完成SecurityFilterChain具有十五个基本的Filter:

    十五个基本的Filter


配置WebSecurity

配置完默认基本的SecurityFilterChain后,将会配置WebSecurity

我们看到WebSecurityConfiguration

先看它是如何配置WebSecurity的,如下:

WebrSecurityConfiguration.java

@Autowired(required = false)
public void setFilterChainProxySecurityConfigurer(ObjectPostProcessor<Object> objectPostProcessor,
      @Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers)//1
      throws Exception {
    
    
   this.webSecurity = objectPostProcessor.postProcess(new WebSecurity(objectPostProcessor));
   webSecurityConfigurers.sort(AnnotationAwareOrderComparator.INSTANCE);//2
   Integer previousOrder = null;
   Object previousConfig = null;
   for (SecurityConfigurer<Filter, WebSecurity> config : webSecurityConfigurers) {
    
    
      Integer order = AnnotationAwareOrderComparator.lookupOrder(config);
      previousOrder = order;
      previousConfig = config;
   }//3
   for (SecurityConfigurer<Filter, WebSecurity> webSecurityConfigurer : webSecurityConfigurers) {
    
    
      this.webSecurity.apply(webSecurityConfigurer);
   }//4
   this.webSecurityConfigurers = webSecurityConfigurers;
}
  1. 首先看配有注明@Value的形参,该注释获取了之前配置的所有WebSeucurityConfigurer(也就是自定义的WebSecurityConfigurer),在下方它将把配置器全部传给当前创建的WebSecurity
  2. 创建WebSecurity
  3. 排序获取的(自定义的)SecurityConfigurer
  4. 将获取的(自定义的)SecurityConfigurer配置器传入当前WebSecuirty中,apply使用配置器,自然不用多说

配置最终的FilterChainProxy

配置完WebSecurity,基础的SecurityFilterChain,将配置最终的SecurityFilterChain

WebSecurityConfiguration.java

@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
public Filter springSecurityFilterChain() throws Exception {
    
    
   if (!hasConfigurers && !hasFilterChain) {
    
    
      WebSecurityConfigurerAdapter adapter = this.objectObjectPostProcessor
            .postProcess(new WebSecurityConfigurerAdapter() {
    
    
            });
      this.webSecurity.apply(adapter);
   }//1
   for (SecurityFilterChain securityFilterChain : this.securityFilterChains) {
    
    
      this.webSecurity.addSecurityFilterChainBuilder(() -> securityFilterChain);
      for (Filter filter : securityFilterChain.getFilters()) {
    
    
         if (filter instanceof FilterSecurityInterceptor) {
    
    
            this.webSecurity.securityInterceptor((FilterSecurityInterceptor) filter);
            break;
         }
      }
   }//2
   for (WebSecurityCustomizer customizer : this.webSecurityCustomizers) {
    
    
      customizer.customize(this.webSecurity);
   }//3
   return this.webSecurity.build();//4
}
  1. 如果没有FilterChain则创建FilterChain,无论是自定义还是默认,通常都有FilterChain

  2. WebSecurity设置FilterSecurityInterceptor

  3. 配置自定义的WebSecurity,该自定义类需要实现WebSecurityCustomizer接口

    WebSecurityConfiguration.java

    @Autowired(required = false)
    void setWebSecurityCustomizers(List<WebSecurityCustomizer> webSecurityCustomizers) {
            
            
       this.webSecurityCustomizers = webSecurityCustomizers;
    }
    
  4. 返回最终再经WebSecuriity配置完的SecurityFilterChain(最终版)

    buid()方法就不多讲了,之前配置[HttpSecurity](# 配置HttpSecurity)中的AuthenticationConfiguration时也讲过,这里我们主要解析一下不同继承AbstractConfiguredSecurityBuilderperformBuild()方法

    WebSecurity.java

    @Override
    protected Filter performBuild() throws Exception {
           
           
       int chainSize = this.ignoredRequests.size() + this.securityFilterChainBuilders.size();
       List<SecurityFilterChain> securityFilterChains = new ArrayList<>(chainSize);
       List<RequestMatcherEntry<List<WebInvocationPrivilegeEvaluator>>> requestMatcherPrivilegeEvaluatorsEntries = new ArrayList<>();
       for (RequestMatcher ignoredRequest : this.ignoredRequests) {
           
           
          SecurityFilterChain securityFilterChain = new DefaultSecurityFilterChain(ignoredRequest);
          securityFilterChains.add(securityFilterChain);
          requestMatcherPrivilegeEvaluatorsEntries
                .add(getRequestMatcherPrivilegeEvaluatorsEntry(securityFilterChain));
       }
       for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : this.securityFilterChainBuilders) {
           
           
          SecurityFilterChain securityFilterChain = securityFilterChainBuilder.build();
          securityFilterChains.add(securityFilterChain);
          requestMatcherPrivilegeEvaluatorsEntries
                .add(getRequestMatcherPrivilegeEvaluatorsEntry(securityFilterChain));
       }
       if (this.privilegeEvaluator == null) {
           
           
          this.privilegeEvaluator = new RequestMatcherDelegatingWebInvocationPrivilegeEvaluator(
                requestMatcherPrivilegeEvaluatorsEntries);
       }
       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;
    }
    

    分析一下可以得出,该方法的功能,就是把默认的SecurityFilterChain中的过滤器和WebSecurity的过滤器,加入新创建的FilterChainProxy中,并返回


完结

至此SpringSecurity大致默认启动流程源码分析就结束了

猜你喜欢

转载自blog.csdn.net/HHoao/article/details/124573922