跳到主要内容

Spring Security源码(九):过滤器链上的过滤器是如何排序的?

文章目录

  • 一、框架原理
    • 概述
  • 过滤器链实战示例
  • 二、FilterComparator
    • 源码
  • 说明
  • 自定义过滤器顺序设置
  • 三、如何排序
    • 实际排序
  • FilterSecurityInterceptor
  • 四、系列文章
    • Spring Security 系列
  • Spring Security OAuth 系列

一、框架原理

概述

> 前面源码篇文章(篇尾附上链接)提到,整个框架的核心就是一个过滤器 FilterChainProxy,这个过滤器维护了一组过滤器链,真正起作用的其实是这个过滤器里的过滤器链。我们知道过滤器链可是有执行顺序的,关于它是如何排序的,本篇来聊聊。

过滤器链实战示例

> 先来看看一个请求进来需要走过的过滤器链有哪些,以下为前面实战篇(篇尾附上链接)中过滤器链debug截图,断点打在核心过滤器 FilterChainProxydoFilter() 上,自行走一下代码,会发现请求需要经过如下过滤器:

>  
> 可以看到很多熟悉的过滤器,包括我们自己定义的两个过滤器 UserAuthenticationFilterJwtAuthenticationFilter

二、FilterComparator

> 内部其实是使用这个类来对Filter的实例进行排序,以确保它们的顺序正确。

源码

final class FilterComparator implements Comparator<Filter>, Serializable {


private static final int STEP = 100;
private Map<String, Integer> filterToOrder = new HashMap<String, Integer>();

FilterComparator() {


int order = 100;
put(ChannelProcessingFilter.class, order);
order += STEP;
put(ConcurrentSessionFilter.class, order);
order += STEP;
put(WebAsyncManagerIntegrationFilter.class, order);
order += STEP;
put(SecurityContextPersistenceFilter.class, order);
order += STEP;
put(HeaderWriterFilter.class, order);
order += STEP;
put(CorsFilter.class, order);
order += STEP;
put(CsrfFilter.class, order);
order += STEP;
put(LogoutFilter.class, order);
order += STEP;
put(X509AuthenticationFilter.class, order);
order += STEP;
put(AbstractPreAuthenticatedProcessingFilter.class, order);
order += STEP;
filterToOrder.put("org.springframework.security.cas.web.CasAuthenticationFilter",
order);
order += STEP;
put(UsernamePasswordAuthenticationFilter.class, order);
order += STEP;
put(ConcurrentSessionFilter.class, order);
order += STEP;
filterToOrder.put(
"org.springframework.security.openid.OpenIDAuthenticationFilter", order);
order += STEP;
put(DefaultLoginPageGeneratingFilter.class, order);
order += STEP;
put(ConcurrentSessionFilter.class, order);
order += STEP;
put(DigestAuthenticationFilter.class, order);
order += STEP;
put(BasicAuthenticationFilter.class, order);
order += STEP;
put(RequestCacheAwareFilter.class, order);
order += STEP;
put(SecurityContextHolderAwareRequestFilter.class, order);
order += STEP;
put(JaasApiIntegrationFilter.class, order);
order += STEP;
put(RememberMeAuthenticationFilter.class, order);
order += STEP;
put(AnonymousAuthenticationFilter.class, order);
order += STEP;
put(SessionManagementFilter.class, order);
order += STEP;
put(ExceptionTranslationFilter.class, order);
order += STEP;
put(FilterSecurityInterceptor.class, order);
order += STEP;
put(SwitchUserFilter.class, order);
}

public int compare(Filter lhs, Filter rhs) {


Integer left = getOrder(lhs.getClass());
Integer right = getOrder(rhs.getClass());
return left - right;
}

/**
* Determines if a particular {@link Filter} is registered to be sorted
*
* @param filter
* @return
*/
public boolean isRegistered(Class<? extends Filter> filter) {


return getOrder(filter) != null;
}

/**
* Registers a {@link Filter} to exist after a particular {@link Filter} that is
* already registered.
* @param filter the {@link Filter} to register
* @param afterFilter the {@link Filter} that is already registered and that
* {@code filter} should be placed after.
*/
public void registerAfter(Class<? extends Filter> filter,
Class<? extends Filter> afterFilter) {


Integer position = getOrder(afterFilter);
if (position == null) {


throw new IllegalArgumentException(
"Cannot register after unregistered Filter " + afterFilter);
}

put(filter, position + 1);
}

/**
* Registers a {@link Filter} to exist at a particular {@link Filter} position
* @param filter the {@link Filter} to register
* @param atFilter the {@link Filter} that is already registered and that
* {@code filter} should be placed at.
*/
public void registerAt(Class<? extends Filter> filter,
Class<? extends Filter> atFilter) {


Integer position = getOrder(atFilter);
if (position == null) {


throw new IllegalArgumentException(
"Cannot register after unregistered Filter " + atFilter);
}

put(filter, position);
}

/**
* Registers a {@link Filter} to exist before a particular {@link Filter} that is
* already registered.
* @param filter the {@link Filter} to register
* @param beforeFilter the {@link Filter} that is already registered and that
* {@code filter} should be placed before.
*/
public void registerBefore(Class<? extends Filter> filter,
Class<? extends Filter> beforeFilter) {


Integer position = getOrder(beforeFilter);
if (position == null) {


throw new IllegalArgumentException(
"Cannot register after unregistered Filter " + beforeFilter);
}

put(filter, position - 1);
}

private void put(Class<? extends Filter> filter, int position) {


String className = filter.getName();
filterToOrder.put(className, position);
}

/**
* Gets the order of a particular {@link Filter} class taking into consideration
* superclasses.
*
* @param clazz the {@link Filter} class to determine the sort order
* @return the sort order or null if not defined
*/
private Integer getOrder(Class<?> clazz) {


while (clazz != null) {


Integer result = filterToOrder.get(clazz.getName());
if (result != null) {


return result;
}
clazz = clazz.getSuperclass();
}
return null;
}
}