经过前面十篇文章的流程分析,我们也了解了 SpringSecurity 的初始化流程和几种比较重要的过滤器。这里简单总结一下:

在这篇文章中,我们就来看一下 SpringSecurity 是如何设置这些 Filter 的执行顺序的

SpringSecurity - 启动流程分析(八)- CsrfFilter 过滤器 SpringSecurity - 启动流程分析(九)- CorsFilter 过滤器 中,我们知道默认的 Filter 是通过 HttpSecurity 中的特定方法添加的,比如:

public CorsConfigurer<HttpSecurity> cors() throws Exception {
	return getOrApply(new CorsConfigurer<>());
public CsrfConfigurer<HttpSecurity> csrf() throws Exception {
	ApplicationContext context = getContext();
	return getOrApply(new CsrfConfigurer<>(context));

而自定义的 Filter 则可以通过 addFilter() 等方法添加:

@Override
public HttpSecurity addFilterAfter(Filter filter, Class<? extends Filter> afterFilter) {
	return addFilterAtOffsetOf(filter, 1, afterFilter);
@Override
public HttpSecurity addFilterBefore(Filter filter, Class<? extends Filter> beforeFilter) {
	return addFilterAtOffsetOf(filter, -1, beforeFilter);
private HttpSecurity addFilterAtOffsetOf(Filter filter, int offset, Class<? extends Filter> registeredFilter) {
	int order = this.filterOrders.getOrder(registeredFilter) + offset;
	this.filters.add(new OrderedFilter(filter, order));
	this.filterOrders.put(filter.getClass(), order);
	return this;
@Override
public HttpSecurity addFilter(Filter filter) {
	Integer order = this.filterOrders.getOrder(filter.getClass());
	if (order == null) {
		throw new IllegalArgumentException("The Filter class " + filter.getClass().getName()
				+ " does not have a registered order and cannot be added without a specified order. Consider using addFilterBefore or addFilterAfter instead.");
	this.filters.add(new OrderedFilter(filter, order));
	return this;
public HttpSecurity addFilterAt(Filter filter, Class<? extends Filter> atFilter) {
	return addFilterAtOffsetOf(filter, 0, atFilter);

而那些默认的过滤器,其实也是通过 addFilter() 方法添加的,所以我们接下来主要看一下 HttpSecurityaddFilter() 方法

// HttpSecurity 被创建的时候,会初始化 FilterOrderRegistration
private FilterOrderRegistration filterOrders = new FilterOrderRegistration();
// 存放了所有的 Filter
private List<OrderedFilter> filters = new ArrayList<>();
// 这个方法用于 HttpSecurity 添加默认的过滤器
@Override
public HttpSecurity addFilter(Filter filter) {
	Integer order = this.filterOrders.getOrder(filter.getClass());
	if (order == null) {
		throw new IllegalArgumentException("The Filter class " + filter.getClass().getName()
				+ " does not have a registered order and cannot be added without a specified order. Consider using addFilterBefore or addFilterAfter instead.");
	this.filters.add(new OrderedFilter(filter, order));
	return this;
// 上面的其他几个方法用于添加自定义的过滤器,比如 addFilterAt、addFilterBefore

关于 FilterOrderRegistration,这个类其实就是为了记录 Filter 的类名和顺序:

final class FilterOrderRegistration {
	// 初始顺序
	private static final int INITIAL_ORDER = 100;
	// 顺序步长
	private static final int ORDER_STEP = 100;
	// 以类名为key存放过滤器的顺序
	private final Map<String, Integer> filterToOrder = new HashMap<>();
	// 构造器中初始胡默认的过滤器顺序
	FilterOrderRegistration() {
		Step order = new Step(INITIAL_ORDER, ORDER_STEP);
		put(DisableEncodeUrlFilter.class, order.next());
		put(ForceEagerSessionCreationFilter.class, order.next());
		put(ChannelProcessingFilter.class, order.next());
		order.next(); // gh-8105
		put(WebAsyncManagerIntegrationFilter.class, order.next());
		put(SecurityContextHolderFilter.class, order.next());
		put(SecurityContextPersistenceFilter.class, order.next());
		put(HeaderWriterFilter.class, order.next());
		put(CorsFilter.class, order.next());
		put(CsrfFilter.class, order.next());
		put(LogoutFilter.class, order.next());
		this.filterToOrder.put(
				"org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter",
				order.next());
		this.filterToOrder.put(
				"org.springframework.security.saml2.provider.service.servlet.filter.Saml2WebSsoAuthenticationRequestFilter",
				order.next());
		put(X509AuthenticationFilter.class, order.next());
		put(AbstractPreAuthenticatedProcessingFilter.class, order.next());
		this.filterToOrder.put("org.springframework.security.cas.web.CasAuthenticationFilter", order.next());
		this.filterToOrder.put("org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter",
				order.next());
		this.filterToOrder.put(
				"org.springframework.security.saml2.provider.service.servlet.filter.Saml2WebSsoAuthenticationFilter",
				order.next());
		put(UsernamePasswordAuthenticationFilter.class, order.next());
		order.next(); // gh-8105
		this.filterToOrder.put("org.springframework.security.openid.OpenIDAuthenticationFilter", order.next());
		put(DefaultLoginPageGeneratingFilter.class, order.next());
		put(DefaultLogoutPageGeneratingFilter.class, order.next());
		put(ConcurrentSessionFilter.class, order.next());
		put(DigestAuthenticationFilter.class, order.next());
		this.filterToOrder.put(
				"org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationFilter",
				order.next());
		put(BasicAuthenticationFilter.class, order.next());
		put(RequestCacheAwareFilter.class, order.next());
		put(SecurityContextHolderAwareRequestFilter.class, order.next());
		put(JaasApiIntegrationFilter.class, order.next());
		put(RememberMeAuthenticationFilter.class, order.next());
		put(AnonymousAuthenticationFilter.class, order.next());
		this.filterToOrder.put("org.springframework.security.oauth2.client.web.OAuth2AuthorizationCodeGrantFilter",
				order.next());
		put(SessionManagementFilter.class, order.next());
		put(ExceptionTranslationFilter.class, order.next());
		put(FilterSecurityInterceptor.class, order.next());
		put(AuthorizationFilter.class, order.next());
		put(SwitchUserFilter.class, order.next());
	// 存放指定类的顺序,如果重复则直接返回
	void put(Class<? extends Filter> filter, int position) {
		String className = filter.getName();
		if (this.filterToOrder.containsKey(className)) {
			return;
		this.filterToOrder.put(className, position);
	// 获取指定类的顺序,如果为空,尝试获取父类的顺序
	Integer getOrder(Class<?> clazz) {
		while (clazz != null) {
			Integer result = this.filterToOrder.get(clazz.getName());
			if (result != null) {
				return result;
			clazz = clazz.getSuperclass();
		return null;
	// 给定初始步数和步长,获取下一个步数
	private static class Step {
		private int value;
		private final int stepSize;
		Step(int initialValue, int stepSize) {
			this.value = initialValue;
			this.stepSize = stepSize;
		int next() {
			int value = this.value;
			this.value += this.stepSize;
			return value;

OrderedFilterHttpSecurity 的内部类,实现了 OrderedFilter 接口:

private static final class OrderedFilter implements Ordered, Filter {
	private final Filter filter;
	private final int order;
	private OrderedFilter(Filter filter, int order) {
		this.filter = filter;
		this.order = order;
	@Override
	public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
			throws IOException, ServletException {
		this.filter.doFilter(servletRequest, servletResponse, filterChain);
	@Override
	public int getOrder() {
		return this.order;
	@Override
	public String toString() {
		return "OrderedFilter{" + "filter=" + this.filter + ", order=" + this.order + '}';

所有的 Filters 存储在 HttpSecurityfilters 属性中,最后由 performBuild() 方法封装为 DefaultSecurityFilterChain

注意:这里我使用的是 spring-security-5.7.2spring-security-5.4.6 代码还是有些不同的,不过殊途同归,都是使用 Comparator 做比较,关于 Comparator 不理解的可以查看 Java - 浅析 Comparable 和 Comparator 这篇文章。

@Override
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);
	// 排好序的 Filter
	List<Filter> sortedFilters = new ArrayList<>(this.filters.size());
	for (Filter filter : this.filters) {
		sortedFilters.add(((OrderedFilter) filter).filter);
	return new DefaultSecurityFilterChain(this.requestMatcher, sortedFilters);

以上就是 SpringSecurityFilter 的顺序,经过前面的分析,逻辑还是很清晰的,不得不说,Spring 的代码,真是一环套一环,跟标准答案一样。

赠送jar包:spring-security-crypto-5.5.2.jar; 赠送原API文档:spring-security-crypto-5.5.2-javadoc.jar; 赠送源代码:spring-security-crypto-5.5.2-sources.jar; 赠送Maven依赖信息文件:spring-security-crypto-5.5.2.pom; 包含翻译后的API文档:spring-security-crypto-5.5.2-javadoc-API文档-中文(简体)版.zip; Maven坐标:org.springframework.security:spring-security-crypto:5.5.2; 标签:springframework、securityspring、crypto、中文文档、jar包、java; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构保持不变,注释和说明精准翻译,请放心使用。 spring security在web应用中是通过各种各样的filter来做认证和安全控制的,由于filter之间的依赖性,过滤器链中filter的顺序也极其重要,不管实际项目中我们选用了哪些过滤器。 1.filter顺序 [list] [*]ChannelProcessingFilter,访问协议控制过滤器,可能会将我们重新定向到另外一种协议,如从http转换成https springboot项目整合了springSecurity,所有的controller接口都需要认证通过才能访问。 现在需要对接第三方接口,接收第三方推送的数据。然而第三方推送接口的数据是固定的,不能传认证信息。 在这样的情况下,我们如何接收第三方推送的数据? (注: springSecurity的相关配置不能改动)
赠送jar包:spring-security-oauth2-2.3.5.RELEASE.jar; 赠送原API文档:spring-security-oauth2-2.3.5.RELEASE-javadoc.jar; 赠送源代码:spring-security-oauth2-2.3.5.RELEASE-sources.jar; 赠送Maven依赖信息文件:spring-security-oauth2-2.3.5.RELEASE.pom; 包含翻译后的API文档:spring-security-oauth2-2.3.5.RELEASE-javadoc-API文档-中文(简体)版.zip; Maven坐标:org.springframework.security.oauth:spring-security-oauth2:2.3.5.RELEASE; 标签:springsecurityspringframework、oauth2、oauth、jar包、java、中文文档; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代
赠送jar包:spring-security-core-5.3.9.RELEASE.jar; 赠送原API文档:spring-security-core-5.3.9.RELEASE-javadoc.jar; 赠送源代码:spring-security-core-5.3.9.RELEASE-sources.jar; 赠送Maven依赖信息文件:spring-security-core-5.3.9.RELEASE.pom; 包含翻译后的API文档:spring-security-core-5.3.9.RELEASE-javadoc-API文档-中文(简体)版.zip; Maven坐标:org.springframework.security:spring-security-core:5.3.9.RELEASE; 标签:springframework、securityspring、core、中文文档、jar包、java; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构保持不变,注释和说明精准翻译,请放心使用。
赠送jar包:spring-security-web-5.6.1.jar; 赠送原API文档:spring-security-web-5.6.1-javadoc.jar; 赠送源代码:spring-security-web-5.6.1-sources.jar; 赠送Maven依赖信息文件:spring-security-web-5.6.1.pom; 包含翻译后的API文档:spring-security-web-5.6.1-javadoc-API文档-中文(简体)版.zip; Maven坐标:org.springframework.security:spring-security-web:5.6.1; 标签:springsecurity、web、springframework、jar包、java、中文文档; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构保持不变,注释和说明精准翻译,请放心使用。 @Bean public FilterRegistrationBean resourceFilterRegistration() { FilterRegistrationBean frBean = new FilterRegistrationBean(); frBean.setFilter(res...
这文章主要用来分析Spring Security中的过滤器链包含了哪些关键的过滤器,并且各自的作用是什么。 一、 Filter顺序 Spring Security的官方文档向我们提供了filter的顺序,无论实际应用中你用到了哪些,整体的顺序是保持不变的: ChannelProcessingFilter,重定向到其他协议的过滤器。也就是说如果你访问的channel错了,那首先就会在channel之间进行跳转,如http变为https。 SecurityContextPersistenceFilter,请
Security Filters顺序 ​ Security Filter通过SecurityFilterChain 被插入到FilterChainProxy中。过滤器的顺序很重要,但通常不需要知道Spring Security过滤器的顺序。然而,有些时候,知道顺序是有益的。 你可以通过FilterOrderRegistration查看过滤器的顺序 FilterOrderRegistration.java FilterOrderRegistration() { Step order = new S
Spring Security过滤器与Servlet过滤器执行顺序是不同的。 在Spring Security中,过滤器链是通过DelegatingFilterProxy来管理的。DelegatingFilterProxy是一个Servlet过滤器,它将请求委托给Spring上下文中的一个或多个Spring Security过滤器链进行处理。在Spring Security过滤器链中,过滤器执行顺序是由其在配置文件中的顺序决定的。 一般而言,Spring Security过滤器链包括了很多过滤器,如UsernamePasswordAuthenticationFilter、BasicAuthenticationFilter、LogoutFilter等。这些过滤器按照特定的顺序依次执行,从而完成身份验证、授权、注销等安全功能。 而普通的Servlet过滤器是通过web.xml文件配置并按照配置的顺序执行的。Servlet容器根据web.xml中的<filter>和<filter-mapping>标签的顺序来确定过滤器执行顺序。 因此,Spring Security过滤器链和Servlet过滤器执行顺序是不同的,需要根据具体情况来确定。一般而言,Spring Security过滤器会在Servlet过滤器之前执行。