我们使用的是使用AbstractSecurityWebApplicationInitializer
初始化的Spring安全性。我们还有一个单独的网络应用初始值设定项,从AbstractAnnotationConfigDispatcherServletInitializer
扩展而来。我按照前者Javadoc的建议将@Order(Ordered.HIGHEST_PRECEDENCE)
作为后者。到目前为止一切都很好。
现在我想介绍一些与Spring安全无关的其他Servlet过滤器,因此应该单独配置。我知道我可以使用DelegatingFilterProxy
将请求委托给过滤器。但DelegatingFilterProxy
无法接受多个过滤器。
一种选择是在Spring Security FilterChain
中定义自定义FilterChainProxy
。这仍然会创建2个DelegatingFilterProxy
,我知道应用中应该只有一个DelegatingFilterProxy
。
有什么想法吗?
答案 0 :(得分:0)
回答我自己的问题,我就这样做了:
我将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);
}