为了让系统正常运行,SecurityFilterChain 上的Filter要保持一定的顺序,例如AuthorizationFilter 要放在各类AuthenticationFilter 的后面,不然还没认证就开始校验权限信息,那一定不会通过。
Spring Security为默认的Filter设置了固定的顺序,这些Filter和Filter的子类,都会按照这个顺序执行。
重要限制
所有Filter都要设置顺序值,可以使用HttpSecurity 的 addFilterAfter(Filter filter, Class<? extends Filter> afterFilter) 和addFilterBefore(Filter filter, Class<? extends Filter> beforeFilter) 方法来添加Filter,方法的第二个参数就是下面默认的Filter类型。
Filter默认顺序
Spring Security在FilterOrderRegistration类中设置了Filter类型的默认顺序。然后在添加Filter时,会根据Filter类型获取Order。
设置顺序是在构造函数实现,获取顺序是在getOrder(Class<?> clazz)方法,会根据Filter类型或父类型找到顺序值。
FilterOrderRegistration() {
// INITIAL_ORDER、ORDER_STEP值默认为100
Step order = new Step(INITIAL_ORDER, ORDER_STEP);
// order.next()会返回当前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.web.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.web.authentication.Saml2WebSsoAuthenticationFilter",
order.next());
put(UsernamePasswordAuthenticationFilter.class, order.next());
order.next(); // gh-8105
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.authentication.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());
}
Integer getOrder(Class<?> clazz) {
while (clazz != null) {
Integer result = this.filterToOrder.get(clazz.getName());
if (result != null) {
return result;
}
clazz = clazz.getSuperclass();
}
return null;
}
排序规则
在把Filter添加到SecurityFilterChain之前,会对所有Filter进行排序。排序使用OrderComparator类提供的规则:
Filter是PriorityOrdered的子类,那么排在最前面
Filter的Ordered值越小,排名越靠前