SpringSecurity - 启动流程分析(十一)- 过滤器的执行顺序

本文详细解析了SpringSecurity中过滤器的执行顺序设定过程,包括默认过滤器和自定义过滤器的添加方式,以及FilterOrderRegistration类如何记录过滤器顺序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

经过前面十篇文章的流程分析,我们也了解了 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 的代码,真是一环套一环,跟标准答案一样。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值