我们正在使用使用 AbstractSecurityWebApplicationInitializer
初始化的 Spring 安全性。我们还有一个单独的 Web 应用初始化程序,它从 AbstractAnnotationConfigDispatcherServletInitializer
扩展而来。按照前者的 Javadoc 中的建议,我将后者设为 @Order(Ordered.HIGHEST_PRECEDENCE)
。到目前为止一切顺利。
现在我想介绍额外的 Servlet 过滤器,它们与 Spring 安全性无关,因此应该单独配置。我知道我可以使用 DelegatingFilterProxy
将请求委托(delegate)给过滤器。但是 DelegatingFilterProxy
没有接受多个过滤器的能力。
一种选择是定义自定义 FilterChain
,如 Spring Security FilterChainProxy
中所做的那样。这仍然会创建 2 个 DelegatingFilterProxy
,我知道应用程序中应该只有一个 DelegatingFilterProxy
。
有什么想法吗?
最佳答案
回答我自己的问题,我是这样做的:
我将 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);
}
关于spring-mvc - 如何将 Spring DelegatingFilterProxy 与多个过滤器和 Spring Security 一起使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30200841/