• Spring Security Filter Chain


    1. 简介

    Spring Security中的所有功能都是通过过滤器来实现的,这些过滤器组成一个完整的过滤器链。过滤器链涉及很多基础组件,首先梳理一下这些关键组件,会方便理解Spring Security过滤器链。

    2. ObjectPostProcessor

    他是一个对象后置处理器,当一个对象创建成功后,如果需要一些额外的事情需要补充,就可以通过ObjectPostProcessor来进行处理。

    在Spring Security中,开发者可以灵活的配置项目中需要哪些过滤器,一旦选定过滤器之后,每个过滤器会有一个对应的配置器,叫做xxxConfigurer(例如CorsConfigurer),过滤器都是在xxxConfigurer中new出来的,然后再postProcess方法中处理一遍,就将这些过滤器注入到Spring容器中了

    1. public interface ObjectPostProcessor {
    2. extends T> O postProcess(O object);
    3. }

    默认有两个继承类,继承关系如下

    2.1  AutowireBeanFactoryObjectPostProcessor

    当一个对象被new出来以后,只要调用AutowireBeanFactoryObjectPostProcessor#postProcess方法,就可以成功注入到Spring容器中。

    1. @Override
    2. @SuppressWarnings("unchecked")
    3. public T postProcess(T object) {
    4. if (object == null) {
    5. return null;
    6. }
    7. T result = null;
    8. try {
    9. result = (T) this.autowireBeanFactory.initializeBean(object, object.toString());
    10. }
    11. catch (RuntimeException ex) {
    12. Class type = object.getClass();
    13. throw new RuntimeException("Could not postProcess " + object + " of type " + type, ex);
    14. }
    15. this.autowireBeanFactory.autowireBean(object);
    16. if (result instanceof DisposableBean) {
    17. this.disposableBeans.add((DisposableBean) result);
    18. }
    19. if (result instanceof SmartInitializingSingleton) {
    20. this.smartSingletons.add((SmartInitializingSingleton) result);
    21. }
    22. return result;
    23. }

    2.2  CompositeObjectPostProcessor

    他是一个组合的对象后置处理器,维护了一个List集合,存放了所有的后置处理器。在Spring Security框架中,最终使用的对象后置处理器其实就是CompositeObjectPostProcessor,他里面的集合默认只有一个对象,就是AutowireBeanFactoryObjectPostProcessor。

    1. private static final class CompositeObjectPostProcessor implements ObjectPostProcessor {
    2. private List> postProcessors = new ArrayList<>();
    3. @Override
    4. @SuppressWarnings({ "rawtypes", "unchecked" })
    5. public Object postProcess(Object object) {
    6. for (ObjectPostProcessor opp : this.postProcessors) {
    7. Class oppClass = opp.getClass();
    8. Class oppType = GenericTypeResolver.resolveTypeArgument(oppClass, ObjectPostProcessor.class);
    9. if (oppType == null || oppType.isAssignableFrom(object.getClass())) {
    10. object = opp.postProcess(object);
    11. }
    12. }
    13. return object;
    14. }
    15. }
    16. 3. SecurityFilterChain

      SecurityFilterChain是Spring Security中的过滤器链对象

      1. public interface SecurityFilterChain {
      2. //用来判断request请求是否应该被当前过滤器链处理
      3. boolean matches(HttpServletRequest request);
      4. //如果matches返回true,那么request请求就会在getFilters方法返回的Filter集合中被处理
      5. List getFilters();
      6. }

      他的默认实现类是DefaultSecurityFilterChain,需要注意的点是,在一个Spring Security项目中,SecurityFilterChain实例可能有多个。

      1. //省略部分代码
      2. public final class DefaultSecurityFilterChain implements SecurityFilterChain {
      3. private final RequestMatcher requestMatcher;
      4. private final List filters;
      5. @Override
      6. public List getFilters() {
      7. return this.filters;
      8. }
      9. @Override
      10. public boolean matches(HttpServletRequest request) {
      11. return this.requestMatcher.matches(request);
      12. }
      13. }

      4. SecurityBuilder

      Spring Security中很多对象都可以通过SecurityBuilder来构建,源码如下:

      1. public interface SecurityBuilder {
      2. O build() throws Exception;
      3. }

      4.1 HttpSecurityBuilder

      用来构建HttpSecurity对象,最终构建出来的对象为DefaultSecurityFilterChain,默认构建后的filter顺序如下:

      HttpSecurityBuilder源码如下:

      1. //HttpSecurityBuilder默认实现类只有HttpSecurity,可以把H当作HttpSecurity
      2. public interface HttpSecurityBuilderextends HttpSecurityBuilder> extends SecurityBuilder {
      3. extends SecurityConfigurer> C getConfigurer(Class clazz);
      4. extends SecurityConfigurer> C removeConfigurer(Class clazz);
      5. //设置可以在多个配置器之间共享的对象
      6. void setSharedObject(Class sharedType, C object);
      7. C getSharedObject(Class sharedType);
      8. //配置认证器AuthenticationProvider
      9. H authenticationProvider(AuthenticationProvider authenticationProvider);
      10. //配置数据源
      11. H userDetailsService(UserDetailsService userDetailsService) throws Exception;
      12. H addFilterAfter(Filter filter, Class afterFilter);
      13. H addFilterBefore(Filter filter, Class beforeFilter);
      14. //这个过滤器必须是Spring Security框架提供的过滤器的实例或者扩展,添加完成后,会自动进行排序
      15. H addFilter(Filter filter);
      16. }

      4.2 AbstractSecurityBuilder

      AbstractSecurityBuilder实现了SecurityBuilder接口,并对build做了完善,确保只build一次。

      1. public abstract class AbstractSecurityBuilder implements SecurityBuilder {
      2. private AtomicBoolean building = new AtomicBoolean();
      3. private O object;
      4. //设置为final,确保子类不会再重写这个方法
      5. @Override
      6. public final O build() throws Exception {
      7. if (this.building.compareAndSet(false, true)) {
      8. this.object = doBuild();
      9. return this.object;
      10. }
      11. throw new AlreadyBuiltException("This object has already been built");
      12. }
      13. public final O getObject() {
      14. if (!this.building.get()) {
      15. throw new IllegalStateException("This object has not been built");
      16. }
      17. return this.object;
      18. }
      19. protected abstract O doBuild() throws Exception;
      20. }

      4.3 AbstractConfiguredSecurityBuilder

      它允许securityconfigururer被应用到它。这使得修改SecurityBuilder成为一种策略,它可以被自定义,并分解成许多securityconfigururer对象,这些对象比SecurityBuilder有更具体的目标。

      例如,一个SecurityBuilder可以构建一个DelegatingFilterProxy,但是一个securityconfiger可以用会话管理、基于表单的登录、授权等所需的过滤器填充SecurityBuilder。

      在这个类中有一个声明了一个枚举,用来描述构建过程的不同状态。

      1. private static enum BuildState {
      2. UNBUILT(0),
      3. INITIALIZING(1),
      4. CONFIGURING(2),
      5. BUILDING(3),
      6. BUILT(4);
      7. private final int order;
      8. private BuildState(int order) {
      9. this.order = order;
      10. }
      11. public boolean isInitializing() {
      12. return INITIALIZING.order == this.order;
      13. }
      14. public boolean isConfigured() {
      15. return this.order >= CONFIGURING.order;
      16. }
      17. }

      在AbstractConfiguredSecurityBuilder中与configurers相关的部分代码如下:

      1. public abstract class AbstractConfiguredSecurityBuilderextends SecurityBuilder> extends AbstractSecurityBuilder {
      2. private final LinkedHashMapextends SecurityConfigurer>, List>> configurers;
      3. private final List> configurersAddedInInitializing;
      4. private final Map, Object> sharedObjects;
      5. private final boolean allowConfigurersOfSameType;
      6. private BuildState buildState;
      7. private ObjectPostProcessor objectPostProcessor;
      8. //向configures变量添加配置类,调用add方法
      9. public extends SecurityConfigurerAdapter> C apply(C configurer) throws Exception {
      10. configurer.addObjectPostProcessor(this.objectPostProcessor);
      11. configurer.setBuilder(this);
      12. this.add(configurer);
      13. return configurer;
      14. }
      15. public extends SecurityConfigurer> C apply(C configurer) throws Exception {
      16. this.add(configurer);
      17. return configurer;
      18. }
      19. //将所有的配置类保存到configures中,默认情况下,allowConfigurersOfSameType为false,所以List集合中的
      20. //配置类始终只有一个
      21. private extends SecurityConfigurer> void add(C configurer) {
      22. Assert.notNull(configurer, "configurer cannot be null");
      23. Classextends SecurityConfigurer> clazz = configurer.getClass();
      24. synchronized(this.configurers) {
      25. if (this.buildState.isConfigured()) {
      26. throw new IllegalStateException("Cannot apply " + configurer + " to already built object");
      27. } else {
      28. List> configs = null;
      29. if (this.allowConfigurersOfSameType) {
      30. configs = (List)this.configurers.get(clazz);
      31. }
      32. List> configs = configs != null ? configs : new ArrayList(1);
      33. ((List)configs).add(configurer);
      34. this.configurers.put(clazz, configs);
      35. if (this.buildState.isInitializing()) {
      36. this.configurersAddedInInitializing.add(configurer);
      37. }
      38. }
      39. }
      40. }
      41. }
      42.  在AbstractConfiguredSecurityBuilder中与构建相关的部分代码如下:

        1. //一边更新状态,一边执行构建方法
        2. protected final O doBuild() throws Exception {
        3. synchronized(this.configurers) {
        4. this.buildState = AbstractConfiguredSecurityBuilder.BuildState.INITIALIZING;
        5. this.beforeInit();
        6. this.init();
        7. this.buildState = AbstractConfiguredSecurityBuilder.BuildState.CONFIGURING;
        8. this.beforeConfigure();
        9. this.configure();
        10. this.buildState = AbstractConfiguredSecurityBuilder.BuildState.BUILDING;
        11. O result = this.performBuild();
        12. this.buildState = AbstractConfiguredSecurityBuilder.BuildState.BUILT;
        13. return result;
        14. }
        15. }
        16. protected void beforeInit() throws Exception {
        17. }
        18. protected void beforeConfigure() throws Exception {
        19. }
        20. protected abstract O performBuild() throws Exception;
        21. //遍历所有配置类,并调用其init方法完成初始化操作
        22. private void init() throws Exception {
        23. Collection> configurers = getConfigurers();
        24. for (SecurityConfigurer configurer : configurers) {
        25. configurer.init((B) this);
        26. }
        27. for (SecurityConfigurer configurer : this.configurersAddedInInitializing) {
        28. configurer.init((B) this);
        29. }
        30. }
        31. private void configure() throws Exception {
        32. Collection> configurers = getConfigurers();
        33. for (SecurityConfigurer configurer : configurers) {
        34. configurer.configure((B) this);
        35. }
        36. }

        4.4 ProviderManagerBuilder

        ProviderManagerBuilder通过范型指定构建对象为AuthenticationManager

        1. public interface ProviderManagerBuilderextends ProviderManagerBuilder>
        2. extends SecurityBuilder {
        3. B authenticationProvider(AuthenticationProvider authenticationProvider);
        4. }

        4.5  AuthenticationManagerBuilder

        AuthenticationManagerBuilder用来构建AuthenticationManager对象,他继承自AbstractConfiguredSecurityBuilder,并且实现了ProviderManagerBuilder,部分代码如下

        1. public class AuthenticationManagerBuilder extends AbstractConfiguredSecurityBuilder implements ProviderManagerBuilder {
        2. private AuthenticationManager parentAuthenticationManager;
        3. private List authenticationProviders = new ArrayList();
        4. private UserDetailsService defaultUserDetailsService;
        5. private Boolean eraseCredentials;
        6. private AuthenticationEventPublisher eventPublisher;
        7. //表示允许相同类型的配置类同时存在
        8. public AuthenticationManagerBuilder(ObjectPostProcessor objectPostProcessor) {
        9. super(objectPostProcessor, true);
        10. }
        11. public AuthenticationManagerBuilder parentAuthenticationManager(AuthenticationManager authenticationManager) {
        12. if (authenticationManager instanceof ProviderManager) {
        13. this.eraseCredentials(((ProviderManager)authenticationManager).isEraseCredentialsAfterAuthentication());
        14. }
        15. this.parentAuthenticationManager = authenticationManager;
        16. return this;
        17. }
        18. public AuthenticationManagerBuilder eraseCredentials(boolean eraseCredentials) {
        19. this.eraseCredentials = eraseCredentials;
        20. return this;
        21. }
        22. //配置基于内存的数据源,会创建一个InMemoryUserDetailsManagerConfigurer配置类,并最终
        23. //将该配置类添加到父类的configurers变量中,由于设置了允许相同类型的配置类同时存在
        24. //因此该方法可以被调用多次
        25. public InMemoryUserDetailsManagerConfigurer inMemoryAuthentication() throws Exception {
        26. return (InMemoryUserDetailsManagerConfigurer)this.apply(new InMemoryUserDetailsManagerConfigurer());
        27. }
        28. public JdbcUserDetailsManagerConfigurer jdbcAuthentication() throws Exception {
        29. return (JdbcUserDetailsManagerConfigurer)this.apply(new JdbcUserDetailsManagerConfigurer());
        30. }
        31. public extends UserDetailsService> DaoAuthenticationConfigurer userDetailsService(T userDetailsService) throws Exception {
        32. this.defaultUserDetailsService = userDetailsService;
        33. return (DaoAuthenticationConfigurer)this.apply(new DaoAuthenticationConfigurer(userDetailsService));
        34. }
        35. public AuthenticationManagerBuilder authenticationProvider(AuthenticationProvider authenticationProvider) {
        36. this.authenticationProviders.add(authenticationProvider);
        37. return this;
        38. }
        39. //创建和配置AuthenticationManager的实现类ProviderManager
        40. //ProviderManager创建成功后,会调用后置处理器处理一遍后再返回
        41. protected ProviderManager performBuild() throws Exception {
        42. if (!this.isConfigured()) {
        43. this.logger.debug("No authenticationProviders and no parentAuthenticationManager defined. Returning null.");
        44. return null;
        45. } else {
        46. ProviderManager providerManager = new ProviderManager(this.authenticationProviders, this.parentAuthenticationManager);
        47. if (this.eraseCredentials != null) {
        48. providerManager.setEraseCredentialsAfterAuthentication(this.eraseCredentials);
        49. }
        50. if (this.eventPublisher != null) {
        51. providerManager.setAuthenticationEventPublisher(this.eventPublisher);
        52. }
        53. providerManager = (ProviderManager)this.postProcess(providerManager);
        54. return providerManager;
        55. }
        56. }
        57. private extends UserDetailsAwareConfigurerextends UserDetailsService>> C apply(C configurer) throws Exception {
        58. this.defaultUserDetailsService = configurer.getUserDetailsService();
        59. return (UserDetailsAwareConfigurer)super.apply(configurer);
        60. }
        61. }
        62. 4.6 HttpSecurity

          HttpSecurity的主要作用是用来构建一条过滤器链,也就是构建一个DefaultSecurityFilterChain对象。一个DefaultSecurityFilterChain对象包含一个路径匹配器和多个Spring Security过滤器,HttpSecurity中通过收集各种各样的xxxConfigurer,将Spring Security过滤器对应的配置类收集起来,并保存到父类AbstractConfiguredSecurityBuilder的configurers变量中。

          在后续的构建过程中,再将这些xxxConfigurer构建为具体的Spring Security过滤器,并添加到filters对象中。

        63. 相关阅读:
          python 图片爬虫记录
          coreldraw2024版本有哪些新增功能?
          html主页框架,前端首页通用架构,layui主页架构框架,首页框架模板
          【无标题】
          推荐 7 个本周 yyds 的开源项目
          “遥遥领先”已被注册为商标,华为这次真的在行业里遥遥领先
          WebSocket vs SSE: 实时数据推送到前端的选择与实现(详细)
          将虚拟机VMware从C盘移动到E盘
          webpack PostCSS工具
          springcloudalibaba架构(7):Sentinel授权规则和系统规则
        64. 原文地址:https://blog.csdn.net/qq_39385118/article/details/126230651