1. 简介

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

2. ObjectPostProcessor

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

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

public interface ObjectPostProcessor<T> {
    <O extends T> O postProcess(O object);
}

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

spring security过滤器顺序 spring security过滤器链_ide

2.1  AutowireBeanFactoryObjectPostProcessor

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

@Override
	@SuppressWarnings("unchecked")
	public <T> T postProcess(T object) {
		if (object == null) {
			return null;
		}
		T result = null;
		try {
			result = (T) this.autowireBeanFactory.initializeBean(object, object.toString());
		}
		catch (RuntimeException ex) {
			Class<?> type = object.getClass();
			throw new RuntimeException("Could not postProcess " + object + " of type " + type, ex);
		}
		this.autowireBeanFactory.autowireBean(object);
		if (result instanceof DisposableBean) {
			this.disposableBeans.add((DisposableBean) result);
		}
		if (result instanceof SmartInitializingSingleton) {
			this.smartSingletons.add((SmartInitializingSingleton) result);
		}
		return result;
	}

2.2  CompositeObjectPostProcessor

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

private static final class CompositeObjectPostProcessor implements ObjectPostProcessor<Object> {

		private List<ObjectPostProcessor<?>> postProcessors = new ArrayList<>();

		@Override
		@SuppressWarnings({ "rawtypes", "unchecked" })
		public Object postProcess(Object object) {
			for (ObjectPostProcessor opp : this.postProcessors) {
				Class<?> oppClass = opp.getClass();
				Class<?> oppType = GenericTypeResolver.resolveTypeArgument(oppClass, ObjectPostProcessor.class);
				if (oppType == null || oppType.isAssignableFrom(object.getClass())) {
					object = opp.postProcess(object);
				}
			}
			return object;
		}

	}

3. SecurityFilterChain

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

public interface SecurityFilterChain {

    //用来判断request请求是否应该被当前过滤器链处理
	boolean matches(HttpServletRequest request);

    //如果matches返回true,那么request请求就会在getFilters方法返回的Filter集合中被处理
	List<Filter> getFilters();

}

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

//省略部分代码
public final class DefaultSecurityFilterChain implements SecurityFilterChain {

	private final RequestMatcher requestMatcher;

	private final List<Filter> filters;

	@Override
	public List<Filter> getFilters() {
		return this.filters;
	}

	@Override
	public boolean matches(HttpServletRequest request) {
		return this.requestMatcher.matches(request);
	}

}

4. SecurityBuilder

spring security过滤器顺序 spring security过滤器链_spring security_02

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

public interface SecurityBuilder<O> {
    O build() throws Exception;
}

4.1 HttpSecurityBuilder

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

spring security过滤器顺序 spring security过滤器链_List_03

HttpSecurityBuilder源码如下:

//HttpSecurityBuilder默认实现类只有HttpSecurity,可以把H当作HttpSecurity
public interface HttpSecurityBuilder<H extends HttpSecurityBuilder<H>> extends SecurityBuilder<DefaultSecurityFilterChain> {

    <C extends SecurityConfigurer<DefaultSecurityFilterChain, H>> C getConfigurer(Class<C> clazz);

    <C extends SecurityConfigurer<DefaultSecurityFilterChain, H>> C removeConfigurer(Class<C> clazz);

    //设置可以在多个配置器之间共享的对象
    <C> void setSharedObject(Class<C> sharedType, C object);

    <C> C getSharedObject(Class<C> sharedType);

    //配置认证器AuthenticationProvider
    H authenticationProvider(AuthenticationProvider authenticationProvider);

    //配置数据源
    H userDetailsService(UserDetailsService userDetailsService) throws Exception;

    H addFilterAfter(Filter filter, Class<? extends Filter> afterFilter);

    H addFilterBefore(Filter filter, Class<? extends Filter> beforeFilter);

    //这个过滤器必须是Spring Security框架提供的过滤器的实例或者扩展,添加完成后,会自动进行排序
	H addFilter(Filter filter);
}

4.2 AbstractSecurityBuilder

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

public abstract class AbstractSecurityBuilder<O> implements SecurityBuilder<O> {

	private AtomicBoolean building = new AtomicBoolean();

	private O object;

    //设置为final,确保子类不会再重写这个方法
	@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 final O getObject() {
		if (!this.building.get()) {
			throw new IllegalStateException("This object has not been built");
		}
		return this.object;
	}

	protected abstract O doBuild() throws Exception;

}

4.3 AbstractConfiguredSecurityBuilder

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

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

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

private static enum BuildState {
        UNBUILT(0),
        INITIALIZING(1),
        CONFIGURING(2),
        BUILDING(3),
        BUILT(4);

        private final int order;

        private BuildState(int order) {
            this.order = order;
        }

        public boolean isInitializing() {
            return INITIALIZING.order == this.order;
        }

        public boolean isConfigured() {
            return this.order >= CONFIGURING.order;
        }
    }

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

public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBuilder<O>> extends AbstractSecurityBuilder<O> {

    private final LinkedHashMap<Class<? extends SecurityConfigurer<O, B>>, List<SecurityConfigurer<O, B>>> configurers;
    private final List<SecurityConfigurer<O, B>> configurersAddedInInitializing;
    private final Map<Class<?>, Object> sharedObjects;
    private final boolean allowConfigurersOfSameType;
    private BuildState buildState;
    private ObjectPostProcessor<Object> objectPostProcessor;

    //向configures变量添加配置类,调用add方法
    public <C extends SecurityConfigurerAdapter<O, B>> C apply(C configurer) throws Exception {
        configurer.addObjectPostProcessor(this.objectPostProcessor);
        configurer.setBuilder(this);
        this.add(configurer);
        return configurer;
    }

    public <C extends SecurityConfigurer<O, B>> C apply(C configurer) throws Exception {
        this.add(configurer);
        return configurer;
    }
    
    //将所有的配置类保存到configures中,默认情况下,allowConfigurersOfSameType为false,所以List集合中的
    //配置类始终只有一个
    private <C extends SecurityConfigurer<O, B>> void add(C configurer) {
        Assert.notNull(configurer, "configurer cannot be null");
        Class<? extends SecurityConfigurer<O, B>> clazz = configurer.getClass();
        synchronized(this.configurers) {
            if (this.buildState.isConfigured()) {
                throw new IllegalStateException("Cannot apply " + configurer + " to already built object");
            } else {
                List<SecurityConfigurer<O, B>> configs = null;
                if (this.allowConfigurersOfSameType) {
                    configs = (List)this.configurers.get(clazz);
                }

                List<SecurityConfigurer<O, B>> configs = configs != null ? configs : new ArrayList(1);
                ((List)configs).add(configurer);
                this.configurers.put(clazz, configs);
                if (this.buildState.isInitializing()) {
                    this.configurersAddedInInitializing.add(configurer);
                }
            }
        }
    }
}

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

//一边更新状态,一边执行构建方法
    protected final O doBuild() throws Exception {
        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;
        }
    }

    protected void beforeInit() throws Exception {
    }

    protected void beforeConfigure() throws Exception {
    }

    protected abstract O performBuild() throws Exception;

    //遍历所有配置类,并调用其init方法完成初始化操作
	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);
		}
	}

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

4.4 ProviderManagerBuilder

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

public interface ProviderManagerBuilder<B extends ProviderManagerBuilder<B>>
		extends SecurityBuilder<AuthenticationManager> {

	B authenticationProvider(AuthenticationProvider authenticationProvider);
}

4.5  AuthenticationManagerBuilder

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

public class AuthenticationManagerBuilder extends AbstractConfiguredSecurityBuilder<AuthenticationManager, AuthenticationManagerBuilder> implements ProviderManagerBuilder<AuthenticationManagerBuilder> {

    private AuthenticationManager parentAuthenticationManager;
    private List<AuthenticationProvider> authenticationProviders = new ArrayList();
    private UserDetailsService defaultUserDetailsService;
    private Boolean eraseCredentials;
    private AuthenticationEventPublisher eventPublisher;

    //表示允许相同类型的配置类同时存在
    public AuthenticationManagerBuilder(ObjectPostProcessor<Object> objectPostProcessor) {
        super(objectPostProcessor, true);
    }

    public AuthenticationManagerBuilder parentAuthenticationManager(AuthenticationManager authenticationManager) {
        if (authenticationManager instanceof ProviderManager) {
            this.eraseCredentials(((ProviderManager)authenticationManager).isEraseCredentialsAfterAuthentication());
        }

        this.parentAuthenticationManager = authenticationManager;
        return this;
    }

    public AuthenticationManagerBuilder eraseCredentials(boolean eraseCredentials) {
        this.eraseCredentials = eraseCredentials;
        return this;
    }

    //配置基于内存的数据源,会创建一个InMemoryUserDetailsManagerConfigurer配置类,并最终
    //将该配置类添加到父类的configurers变量中,由于设置了允许相同类型的配置类同时存在
    //因此该方法可以被调用多次
    public InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder> inMemoryAuthentication() throws Exception {
        return (InMemoryUserDetailsManagerConfigurer)this.apply(new InMemoryUserDetailsManagerConfigurer());
    }

    public JdbcUserDetailsManagerConfigurer<AuthenticationManagerBuilder> jdbcAuthentication() throws Exception {
        return (JdbcUserDetailsManagerConfigurer)this.apply(new JdbcUserDetailsManagerConfigurer());
    }

    public <T extends UserDetailsService> DaoAuthenticationConfigurer<AuthenticationManagerBuilder, T> userDetailsService(T userDetailsService) throws Exception {
        this.defaultUserDetailsService = userDetailsService;
        return (DaoAuthenticationConfigurer)this.apply(new DaoAuthenticationConfigurer(userDetailsService));
    }

    public AuthenticationManagerBuilder authenticationProvider(AuthenticationProvider authenticationProvider) {
        this.authenticationProviders.add(authenticationProvider);
        return this;
    }

    //创建和配置AuthenticationManager的实现类ProviderManager
    //ProviderManager创建成功后,会调用后置处理器处理一遍后再返回
    protected ProviderManager performBuild() throws Exception {
        if (!this.isConfigured()) {
            this.logger.debug("No authenticationProviders and no parentAuthenticationManager defined. Returning null.");
            return null;
        } else {
            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 = (ProviderManager)this.postProcess(providerManager);
            return providerManager;
        }
    }

    private <C extends UserDetailsAwareConfigurer<AuthenticationManagerBuilder, ? extends UserDetailsService>> C apply(C configurer) throws Exception {
        this.defaultUserDetailsService = configurer.getUserDetailsService();
        return (UserDetailsAwareConfigurer)super.apply(configurer);
    }
}

4.6 HttpSecurity

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

在后续的构建过程中,再将这些xxxConfigurer构建为具体的Spring Security过滤器,并添加到HttpSecurity的filters对象中,部分代码如下

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;
    private FilterOrderRegistration filterOrders;
    private AuthenticationManager authenticationManager;
    
    //以form表单登陆配置为例(别的大部分方法都很相似),有两种重载方法可以进行配置,第一种是一个无参formLogin
    //方法,该方法返回一个FormLoginConfigurer<HttpSecurity>对象,开发者在该对象的基础上进行配置
    public FormLoginConfigurer<HttpSecurity> formLogin() throws Exception {
        return (FormLoginConfigurer)this.getOrApply(new FormLoginConfigurer());
    }

    //第二种是传入配置参数实例
    public HttpSecurity formLogin(Customizer<FormLoginConfigurer<HttpSecurity>> formLoginCustomizer) throws Exception {
        formLoginCustomizer.customize((FormLoginConfigurer)this.getOrApply(new FormLoginConfigurer()));
        return this;
    }

    //传入authenticationProvider,最后在beforeConfigure方法中触发AuthenticationManager对象构建
	public HttpSecurity authenticationProvider(AuthenticationProvider authenticationProvider) {
		getAuthenticationRegistry().authenticationProvider(authenticationProvider);
		return this;
	}
	
    //构建DefaultSecurityFilterChain,在此之前会对filters进行排序
    protected DefaultSecurityFilterChain performBuild() {
		ExpressionUrlAuthorizationConfigurer<?> expressionConfigurer = getConfigurer(
				ExpressionUrlAuthorizationConfigurer.class);
		AuthorizeHttpRequestsConfigurer<?> httpConfigurer = getConfigurer(AuthorizeHttpRequestsConfigurer.class);
		boolean oneConfigurerPresent = expressionConfigurer == null ^ httpConfigurer == null;
		Assert.state((expressionConfigurer == null && httpConfigurer == null) || oneConfigurerPresent,
				"authorizeHttpRequests cannot be used in conjunction with authorizeRequests. Please select just one.");
		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);
	}
}

4.7 WebSecurity

相比于HttpSecurity,WebSecurity在一个更大的层面上构建过滤器,WebSecurity负责将HttpSecurity所构建的DefaultSecurityFilterChain对象(可能有多个),以及其他一些需要忽略的请求,再次构建为一个FIlterChainProxy对象,同时添加上Http防火墙,部分核心代码如下:

public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter, WebSecurity> implements SecurityBuilder<Filter>, ApplicationContextAware, ServletContextAware {
 
	private final List<SecurityBuilder<? extends SecurityFilterChain>> securityFilterChainBuilders = new ArrayList<>();

    //保存所有被忽略的请求,不会经过spring security过滤器链
	private final List<RequestMatcher> ignoredRequests = new ArrayList<>();

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

    //在此处构建所有的securityFilterChains,然后将其作为参数构建filterChainProxy
    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;
		if (this.debugEnabled) {
          result = new DebugFilter(filterChainProxy);
		}
		this.postBuildAction.run();
		return result;
	}

}

FilterChainProxy就是我们最终构建出来的过滤器链,通过spring提供的DelegatingFilterProxy将FilterChainProxy对象嵌入到Web Filter中(原生过滤器链)

spring security过滤器顺序 spring security过滤器链_ide_04

5. FilterChainProxy

如上图琐事,FilterChainProxy通过DelegatingFilterProxy代理过滤器被集成到Web Filter中,所以Spring Security中的最终执行的就是FilterChainProxy中的过滤器,部分代码如下:

public class FilterChainProxy extends GenericFilterBean {

	private List<SecurityFilterChain> filterChains;

	private FilterChainValidator filterChainValidator = new NullFilterChainValidator();

	public FilterChainProxy(SecurityFilterChain chain) {
		this(Arrays.asList(chain));
	}

	public FilterChainProxy(List<SecurityFilterChain> filterChains) {
		this.filterChains = filterChains;
	}

    //doFilter方法相当于整个Spring Security过滤器链的入口
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		boolean clearContext = request.getAttribute(FILTER_APPLIED) == null;
		if (!clearContext) {
            //进行实际的filter操作
			doFilterInternal(request, response, chain);
			return;
		}
		try {
			request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
			doFilterInternal(request, response, chain);
		}
		catch (RequestRejectedException ex) {
			this.requestRejectedHandler.handle((HttpServletRequest) request, (HttpServletResponse) response, ex);
		}
		finally {
			SecurityContextHolder.clearContext();
			request.removeAttribute(FILTER_APPLIED);
		}
	}


}

6. SecurityConfigurer

在这两个方法中对SecurityBuilder进行初始化和配置

public interface SecurityConfigurer<O, B extends SecurityBuilder<O>> {

	void init(B builder) throws Exception;

	void configure(B builder) throws Exception;
}