Spring Security 过滤器链(一)创建FilterChainProxy

一.简介

官网官网文档

参考:
深入浅出Spring Security(二):FilterChainProxy的创建过程
Spring Security 源码分析(一):过滤器链
Spring Security源码解析(二.创建FilterChainProxy)
Spring Security(六)—SpringSecurityFilterChain 加载流程深度解析

文中源码均为伪代码,删除了一些的细节

在这里插入图片描述

在SpringSecurity框架中,用户想要访问资源需要经过FilterChainProxy(本质上是个Filter,名字叫springSecurityFilterChain)来过滤。
里面包含一组SecuriyFilterChains,每个uri都对应一个SecurityFilterChain,SecurityFilterChain包含多个SecurityFilter

二.FilterChainProxy的创建

虚线继承/实现,如有错乱以你为准。
在这里插入图片描述
在这里插入图片描述
从图中可以看出

  1. WebSecurityHttpSecurity都是Builder
    WebSecurity是SecurityBuilder< Filter >为了创建FilterChainProxy
    HttpSecurity是SecurityBuilder< DefaultSecurityFilterChain >为了创建 FilterChainProxy的filterChains。
  2. WebSecurityConfigurerAdapter是WebSecurity的Configurer
    WebSecurityConfiguration创建WebSecurity后,赋值给WebSecurity的配置configurers,
    并在WebSecurity要创建FilterChainProxy时,初始化,将HttpSecurity赋值给WebSecurity的securityFilterChainBuilders用于创建过滤器。

1.WebSecurityConfiguration

在这里插入图片描述

1.1 setFilterChainProxySecurityConfigurer()

public void setFilterChainProxySecurityConfigurer(ObjectPostProcessor<Object> objectPostProcessor, @Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers) throws Exception {
        this.webSecurity = (WebSecurity)objectPostProcessor.postProcess(new WebSecurity(objectPostProcessor));
webSecurityConfigurers.sort(WebSecurityConfiguration.AnnotationAwareOrderComparator.INSTANCE);
        Iterator var5;
        SecurityConfigurer config;
        for(var5 = webSecurityConfigurers.iterator(); var5.hasNext(); previousConfig = config) {
            config = (SecurityConfigurer)var5.next();
            Integer order = WebSecurityConfiguration.AnnotationAwareOrderComparator.lookupOrder(config);
            previousOrder = order;
        }

        var5 = webSecurityConfigurers.iterator();

        while(var5.hasNext()) {
            config = (SecurityConfigurer)var5.next();
            this.webSecurity.apply(config);
        }

        this.webSecurityConfigurers = webSecurityConfigurers;
}

该方法负责收集配置类对象列表webSecurityConfigurers,并创建WebSecurity,用于后面建造FilterChainProxy过滤器

@Value("#{@autowiredWebSecurityConfigurersIgnoreParents. getWebSecurityConfigurers()}")
List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers

@Value("#{}") 是SpEl表达式通常用来获取bean的属性或者调用bean的某个方法。
方法执行时,会先得到webSecurityConfigurers并排序(所有实现了WebSecurityConfigurerAdapter的配置类实例)

public List<SecurityConfigurer<Filter, WebSecurity>> getWebSecurityConfigurers() {
        List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers = new ArrayList();
        Map<String, WebSecurityConfigurer> beansOfType = this.beanFactory.getBeansOfType(WebSecurityConfigurer.class);
        Iterator var3 = beansOfType.entrySet().iterator();

        while(var3.hasNext()) {
            Entry<String, WebSecurityConfigurer> entry = (Entry)var3.next();
            webSecurityConfigurers.add(entry.getValue());
        }

        return webSecurityConfigurers;
    }
  • 获取类型为WebSecurityConfigurer的bean

  • this.webSecurity.apply(config)WebSecurityConfigurerAdapter赋值给AbstractConfiguredSecurityBuilder(webSecurity的父类)的configurersAddedInInitializing 和 configurers 【2.1】。

1.2 springSecurityFilterChain()

@Bean( name = {"springSecurityFilterChain"})
public Filter springSecurityFilterChain() throws Exception {
    boolean hasConfigurers = this.webSecurityConfigurers != null && !this.webSecurityConfigurers.isEmpty();
    if (!hasConfigurers) {
        WebSecurityConfigurerAdapter adapter = (WebSecurityConfigurerAdapter)this.objectObjectPostProcessor.postProcess(new WebSecurityConfigurerAdapter() {
        });
        this.webSecurity.apply(adapter);
    }

    return (Filter)this.webSecurity.build();
}

调用webSecurity.build(),建造出FilterChainProxy过滤器对象
并将其命名为"springSecurityFilterChain"

webSecurity.build()–>AbstractSecurityBuilder.build()–>
AbstractConfiguredSecurityBuilder.doBuild()【2.2】

  • init(),configure()
    HttpSecurity添加到webSecurity的属性securityFilterChainBuilders集合里。
  • WebSecurity.performBuild()【3.1】
    securityFilterChainBuilders创建filterchains
    创建FilterChainProxy ;

2.AbstractConfiguredSecurityBuilder

WebSecurity继承AbstractConfiguredSecurityBuilder
在这里插入图片描述
在这里插入图片描述

2.1 apply(C configurer),add(C configurer)

public <C extends SecurityConfigurer<O, B>> C apply(C configurer) throws Exception {
        this.add(configurer);
        return configurer;
}
private <C extends SecurityConfigurer<O, B>> void add(C configurer) {
     Class<? extends SecurityConfigurer<O, B>> clazz = configurer.getClass();
     LinkedHashMap var3 = this.configurers;
     synchronized(this.configurers) {
          List<SecurityConfigurer<O, B>> configs = this.allowConfigurersOfSameType ? (List)this.configurers.get(clazz) : null;
          ((List)configs).add(configurer);
          
          this.configurers.put(clazz, configs);
          this.configurersAddedInInitializing.add(configurer);
     }
 }

2.2 doBuild()

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

2.3 init(),configure()

  • this.init() - >configurer.init(this) - > WebSecurityConfigurerAdapter.init(WebSecurity web) 【4.1】
  • this.configure(this)-> WebSecurityConfigurerAdapter.configure(WebSecurity web) 【4.2.2】;
private void init() throws Exception {
      Collection<SecurityConfigurer<O, B>> configurers = this.getConfigurers();
      Iterator var2 = configurers.iterator();
      SecurityConfigurer configurer;
      while(var2.hasNext()) {
          configurer = (SecurityConfigurer)var2.next();
          configurer.init(this);
      }
      var2 = this.configurersAddedInInitializing.iterator();

      while(var2.hasNext()) {
          configurer = (SecurityConfigurer)var2.next();
          configurer.init(this);
      }
  }
  private void configure() throws Exception {
        Collection<SecurityConfigurer<O, B>> configurers = this.getConfigurers();
        Iterator var2 = configurers.iterator();

        while(var2.hasNext()) {
            SecurityConfigurer<O, B> configurer = (SecurityConfigurer)var2.next();
            configurer.configure(this);
        }

    }

3. WebSecurity

在这里插入图片描述

3.1 performBuild()

protected Filter performBuild() throws Exception {
    // ...
    int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size();
    List<SecurityFilterChain> securityFilterChains = new ArrayList<>(chainSize);
    // 上文配置的需要忽略的请求
    for (RequestMatcher ignoredRequest : ignoredRequests) {
      securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
    }
    // 上文配置的 HttpSecurity 实例
    for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) {
      // 调用 build 方法生成 DefaultSecurityFilterChain
      securityFilterChains.add(securityFilterChainBuilder.build());
    }
    // 过滤器链代理
    FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);

    // ...
  }

创建了FilterChainProxy并用securityFilterChainBuilder配置了FilterChainProxy的过滤器链securityFilterChains

4.WebSecurityConfigurerAdapter

在这里插入图片描述

4.1 init(),getHttp()

public void init(WebSecurity web) throws Exception {
     HttpSecurity http = this.getHttp();
     web.addSecurityFilterChainBuilder(http).postBuildAction(() -> {
         FilterSecurityInterceptor securityInterceptor = (FilterSecurityInterceptor)http.getSharedObject(FilterSecurityInterceptor.class);
         web.securityInterceptor(securityInterceptor);
     });
}
protected final HttpSecurity getHttp() throws Exception {
      AuthenticationManager authenticationManager = this.authenticationManager();
      this.authenticationBuilder.parentAuthenticationManager(authenticationManager);
      this.http = new HttpSecurity(this.objectPostProcessor, this.authenticationBuilder, sharedObjects);
}

WebSecurityConfigurerApdater.init()方法,通过getHttp()方法获得配置好的 HttpSecurity
然后 web.addSecurityFilterChainBuilder(http)HttpSecurity添加到webSecurity的属性securityFilterChainBuilders集合里。

public WebSecurity addSecurityFilterChainBuilder(SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder) {
        this.securityFilterChainBuilders.add(securityFilterChainBuilder);
        return this;
    }

4.2 配置WebSecurityConfigurerAdapter

如果需要干预 spring security 配置,创建MyWebSecurityConfig 继承WebSecurityConfigurerAdapter 并装配到 Spring 容器中。比如

@Configuration
@EnableWebSecurity
@Slf4j
public class MyWebSecurityConfig extends WebSecurityConfigurerAdapter {
}

这里我们可能会重写WebSecurityConfigurerAdapter 中的绿框中的三个configure方法。

4.2.1 configure(HttpSecurity http)

原方法

    protected void configure(HttpSecurity http) throws Exception {
        this.logger.debug("Using default configure(HttpSecurity). If subclassed this will potentially override subclass configure(HttpSecurity).");
        ((HttpSecurity)((HttpSecurity)((AuthorizedUrl)http.authorizeRequests().anyRequest()).authenticated().and()).formLogin().and()).httpBasic();
    }

例子:修改HttpSecurity,重新设置登录,添加filter,修改拦截的路径等

@Override
    protected void configure(HttpSecurity http) throws Exception {
            http
                .formLogin()
                .loginPage("/login")
                .loginProcessingUrl("/login/submit")
                .failureUrl("/login_error").permitAll()
                .and()
                .authorizeRequests()
                    .antMatchers(HttpMethod.GET, "/login").permitAll()
                    .anyRequest().authenticated()
                .and()
                .csrf().disable();

        http.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
    }

4.2.2 configure(WebSecurity web)

原方法

    public void configure(WebSecurity web) throws Exception {
    }

例子:修改WebSecurity 忽略静态资源

@Override
public void configure(WebSecurity web) throws Exception {
    web.ignoring().antMatchers(HttpMethod.GET,  "/*.html","/**/favicon.ico",
            "/**/*.html", "/**/*.css", "/**/*.*.woff", "/**/*.*.woff2", "/**/*.*.ttf","/**/*.js", "/**/*.png",
            "/**/*.jpg", "/**/*.ttf", "/**/*.map","/**/*.tpl","/**/*.map","/**/*.mp4", "/*.txt", "/**/*.txt",
            "/webjars/**","/csrf","/v2/api-docs",
            "/swagger-ui.html", "/swagger-resources/**");
}

4.2.3 configure(AuthenticationManagerBuilder auth)

原方法

protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        this.disableLocalConfigureAuthenticationBldr = true;
    }

例子: 使用customUserService进行用户信息的查询。

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

5. HttpSecurity 16.2

参考
Spring Security : 配置 HttpSecurity 的 SecurityConfigurer
Spring Security原理篇(三) HttpSecurity

用于配置 web 请求的安全配置,默认会应用到所有请求
在上面的configure(HttpSecurity http)中。我们可以修改HttpSecurity 的一些设置。

5.1 默认的过滤器链

Spring Security中HttpSecurity是一个安全构建器SecurityBuilder,目的是构建一个对HTTP请求进行安全控制的DefaultSecurityFilterChain
对HttpSecurity进行配置,是通过一组安全配置器来完成的。这组安全配置器有一个共同的抽象基类AbstractHttpConfigurer。如下:

名称 简介
AnonymousConfigurer 配置匿名认证。 具体来讲,是向HttpSecurity配置一对协调工作的AnonymousAuthenticationFilterAnonymousAuthenticationProvider,所有属性采用合理的缺省值。这样请求处理时,如果SecurityContextHolder中认证对象未设置(null的情况),则向其设置一个匿名认证对象AnonymousAuthenticationToken
ChannelSecurityConfigurer 配置ChannelProcessingFilter
CorsConfigurer 配置CorsFilter
CsrfConfigurer 配置CsrfFilter
DefaultLoginPageConfigurer 配置DefaultLoginPageGeneratingFilter/DefaultLogoutPageGeneratingFilter
ExceptionHandlingConfigurer 配置ExceptionTranslationFilter
ExpressionUrlAuthorizationConfigurer 配置FilterSecurityInterceptor
FormLoginConfigurer 配置UsernamePasswordAuthenticationFilter/DefaultLoginPageGeneratingFilter
HeadersConfigurer 配置HeaderWriterFilter
HttpBasicConfigurer 配置BasicAuthenticationFilter
JeeConfigurer 配置J2eePreAuthenticatedProcessingFilter
LogoutConfigurer 配置LogoutFilter
PortMapperConfigurer 配置共享对象PortMapper,用于HTTP/HTTPS两种协议之间跳转时的端口检测。
RememberMeConfigurer 配置RememberMeAuthenticationFilter
RequestCacheConfigurer 配置RequestCacheAwareFilter
SecurityContextConfigurer 配置SecurityContextPersistenceFilter
ServletApiConfigurer 配置SecurityContextHolderAwareRequestFilter
SessionManagementConfigurer 配置SessionManagementFilter/ConcurrentSessionFilter
X509Configurer 配置X509AuthenticationFilter
OAuth2ClientConfigurer 配置OAuth2AuthorizationRequestRedirectFilter/OAuth2AuthorizationCodeGrantFilter;
配置共享对象:ClientRegistrationRepository
/OAuth2AuthorizedClientRepository
OAuth2LoginConfigurer 配置OAuth2AuthorizationRequestRedirectFilter/OAuth2LoginAuthenticationFilter;
配置共享对象:
ClientRegistrationRepository/
OAuth2AuthorizedClientRepository
/GrantedAuthoritiesMapper
OAuth2ResourceServerConfigurer 配置BearerTokenAuthenticationFilter;
配置共享对象:SessionCreationPolicy
OpenIDLoginConfigurer 配置OpenIDAuthenticationFilter;
配置共享对象:AuthenticationEntryPoint
/OpenIDAuthenticationProvider

比如 http.authorizeRequests()、http.formLogin()、http.httpBasic()分别创建了ExpressionUrlAuthorizationConfigurerFormLoginConfigurerHttpBasicConfigurer。在三个类从父级一直往上找,会发现它们都是SecurityConfigurer建造器的子类。
SecurityConfigurer中又有configure()方法。该方法被子类实现就用于创建各个过滤器,并将过滤器添加进HttpSecurity中维护的装有Filter的List中

5.2 addFilter(Filter) 添加自定义的过滤器

在这里插入图片描述

http.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);

在过滤器链中UsernamePasswordAuthenticationFilter前插入我们自定义的authenticationTokenFilter

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章