如何使用带有多个过滤器和 Spring Security 的 Spring DelegatingFilterProxy?
Posted
技术标签:
【中文标题】如何使用带有多个过滤器和 Spring Security 的 Spring DelegatingFilterProxy?【英文标题】:How to use Spring DelegatingFilterProxy with multiple filters and Spring Security? 【发布时间】:2015-07-23 21:58:17 【问题描述】:我们使用的是使用 AbstractSecurityWebApplicationInitializer
初始化的 Spring 安全性。我们还有一个从 AbstractAnnotationConfigDispatcherServletInitializer
扩展的单独的 Web 应用初始化程序。按照前者的 Javadoc 中的建议,我将后者设置为 @Order(Ordered.HIGHEST_PRECEDENCE)
。到目前为止一切顺利。
现在我想介绍额外的 Servlet 过滤器,这些过滤器与 Spring 安全性无关,因此应该单独配置。我知道我可以使用DelegatingFilterProxy
将请求委托给过滤器。但是DelegatingFilterProxy
没有接受多个过滤器的能力。
一种选择是定义一个自定义的FilterChain
,就像在 Spring Security FilterChainProxy
中所做的那样。这仍然会创建 2 个DelegatingFilterProxy
,我知道应用程序中应该只有一个DelegatingFilterProxy
。
有什么想法吗?
【问题讨论】:
【参考方案1】:回答我自己的问题,我就是这样做的:
我继承了AbstractAnnotationConfigDispatcherServletInitializer
并在其中:
/**
* @inheritDoc
*/
@Override
protected Filter[] getServletFilters()
return new Filter[] requestContextFilter(), teFilterChain() ;
/**
* @inheritDoc
*/
@Override
protected FilterRegistration.Dynamic registerServletFilter(
ServletContext servletContext, Filter filter)
String filterName = Conventions.getVariableName(filter);
Dynamic registration = servletContext.addFilter(filterName, filter);
if (registration == null)
int counter = -1;
while (counter == -1 || registration == null)
counter++;
registration = servletContext
.addFilter(filterName + "#" + counter, filter);
Assert.isTrue(counter < 100, "Failed to register filter '"
+ filter + "'."
+ "Could the same Filter instance have been registered already?");
registration.setAsyncSupported(isAsyncSupported());
registration.addMappingForServletNames(getDispatcherTypes(), false,
getServletName());
return registration;
/**
* Spring, by default, registers filters for 'FORWARD' dispatcher type as
* well which causes TE filter chain to run again after Spring security
* successfully authenticates and forwards the incoming request. We thus
* exclude 'FORWARD' dispatcher type.
*/
private EnumSet<DispatcherType> getDispatcherTypes()
return (isAsyncSupported()
? EnumSet.of(DispatcherType.REQUEST, DispatcherType.INCLUDE,
DispatcherType.ASYNC)
: EnumSet.of(DispatcherType.REQUEST, DispatcherType.INCLUDE));
private Filter requestContextFilter()
return new DelegatingFilterProxy(TE_REQ_CTX_FILTER);
private Filter teFilterChain()
return new DelegatingFilterProxy(TE_FILTER_CHAIN);
@Override
protected void registerDispatcherServlet(ServletContext ctx)
super.registerDispatcherServlet(ctx);
registerSpringSecurityFilter(ctx);
registerCorsFilter(ctx);
@Override
protected DispatcherServlet createDispatcherServlet(
WebApplicationContext servletAppContext)
DispatcherServlet servlet = new DispatcherServlet(servletAppContext);
servlet.setThreadContextInheritable(true);
servlet.setThrowExceptionIfNoHandlerFound(true);
return servlet;
private Dynamic registerCorsFilter(ServletContext ctx)
Dynamic registration = ctx.addFilter("CorsFilter", CorsFilter.class);
registration.setInitParameter(CorsFilter.PARAM_CORS_ALLOWED_ORIGINS,
CORS_ALLOWED_ORIGINS);
registration.setInitParameter(CorsFilter.PARAM_CORS_ALLOWED_METHODS,
CORS_ALLOWED_METHODS);
registration.setInitParameter(CorsFilter.PARAM_CORS_ALLOWED_HEADERS,
CORS_ALLOWED_HEADERS);
registration.addMappingForUrlPatterns(getDispatcherTypes(), false,
"/*");
return registration;
@Override
protected boolean isAsyncSupported()
return true;
private final FilterRegistration.Dynamic registerSpringSecurityFilter(
ServletContext servletContext)
FilterRegistration.Dynamic registration = servletContext.addFilter(
SPRING_SECURITY_FILTER_CHAIN, springSecurityFilterChain());
if (registration == null)
throw new IllegalStateException("Duplicate Filter registration for "
+ SPRING_SECURITY_FILTER_CHAIN
+ "'. Check to ensure the Filter is only configured once.");
registration.setAsyncSupported(isAsyncSupported());
EnumSet<DispatcherType> dispatcherTypes = getSecurityDispatcherTypes();
/*
* Don't use URL mapping for registering Spring security because then
* the chain will kick in before DispatcherServlet.
*/
registration.addMappingForServletNames(dispatcherTypes, true,
getServletName());
return registration;
private Filter springSecurityFilterChain()
return new DelegatingFilterProxy(SPRING_SECURITY_FILTER_CHAIN);
protected EnumSet<DispatcherType> getSecurityDispatcherTypes()
return EnumSet.of(DispatcherType.REQUEST, DispatcherType.ERROR,
DispatcherType.ASYNC);
【讨论】:
你不能使用FilterChainProxy吗? @lqbweb 3.5 年后,我不记得了。以上是关于如何使用带有多个过滤器和 Spring Security 的 Spring DelegatingFilterProxy?的主要内容,如果未能解决你的问题,请参考以下文章
如何在带有自定义过滤器的 Spring Data mongodb 中使用分页和排序?
带有 spring-boot 和 spring-security 的 JWT
如何使用带有 gradle 的多个嵌入式服务器运行 spring-boot 集成测试