经过前面十篇文章的流程分析,我们也了解了
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()
方法添加的,所以我们接下来主要看一下 HttpSecurity
的 addFilter()
方法
private FilterOrderRegistration filterOrders = new FilterOrderRegistration();
private List<OrderedFilter> filters = new ArrayList<>();
@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;
关于 FilterOrderRegistration
,这个类其实就是为了记录 Filter
的类名和顺序:
final class FilterOrderRegistration {
private static final int INITIAL_ORDER = 100;
private static final int ORDER_STEP = 100;
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();
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();
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;
OrderedFilter
是 HttpSecurity
的内部类,实现了 Ordered
、Filter
接口:
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 + '}';
所有的 Filter
s 存储在 HttpSecurity
的 filters
属性中,最后由 performBuild()
方法封装为 DefaultSecurityFilterChain
:
注意:这里我使用的是 spring-security-5.7.2
跟 spring-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);
List<Filter> sortedFilters = new ArrayList<>(this.filters.size());
for (Filter filter : this.filters) {
sortedFilters.add(((OrderedFilter) filter).filter);
return new DefaultSecurityFilterChain(this.requestMatcher, sortedFilters);
以上就是 SpringSecurity
中 Filter
的顺序,经过前面的分析,逻辑还是很清晰的,不得不说,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、
security、
spring、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;
标签:spring、security、springframework、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、
security、
spring、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;
标签:spring、security、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过滤器之前执行。