Spring MVC 3.X升级5.X后Security致登录页返回空200响应求助
从你的描述来看,升级到Spring 5.x后引入Spring Security过滤器链导致登录页返回200但内容为空,核心问题大概率出在Spring Security过滤器的上下文绑定或者自定义CompositeFilter的请求传递逻辑上,结合你的代码给出几个排查和修复方向:
1. 修正DelegatingFilterProxy的上下文属性配置
你当前给DelegatingFilterProxy设置的contextAttribute是DispatcherServlet的上下文属性:
delegatingFilterProxy.setContextAttribute("org.springframework.web.servlet.FrameworkServlet.CONTEXT.dispatcher");
但Spring Security的springSecurityFilterChain是定义在根Spring上下文(由ContextLoaderListener加载)中的,而不是DispatcherServlet的子上下文。在Spring 5.x中,这个上下文绑定的要求更严格,你需要把这个属性去掉,让DelegatingFilterProxy默认从根上下文获取过滤器:
修改代码如下:
DelegatingFilterProxy delegatingFilterProxy = container.createFilter(DelegatingFilterProxy.class); delegatingFilterProxy.setServletContext(container); // 移除下面这行错误的上下文属性配置 // delegatingFilterProxy.setContextAttribute("org.springframework.web.servlet.FrameworkServlet.CONTEXT.dispatcher"); container.addFilter("springSecurityFilterChain", delegatingFilterProxy).addMappingForUrlPatterns(null, false, "/*");
2. 检查自定义CompositeFilter的过滤器实现
你的securityFilters是CompositeFilter,包含sqlInjectionCheckFilter和hostCheckFilter,需要确保这两个自定义过滤器正确调用了FilterChain.doFilter(request, response)。在Spring 5.x中,过滤器如果没有继续传递请求链,会导致响应被截断,返回空内容。
比如你的自定义过滤器应该遵循这个模板:
public class SqlInjectionCheckFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // 你的校验逻辑 // 必须调用这行,否则请求不会继续往下传递到后续过滤器/控制器 chain.doFilter(request, response); } // 其他初始化、销毁方法... }
如果你的旧版本过滤器里遗漏了这行,升级后Spring Security的过滤器链会因为请求被中断而无法渲染登录页。
3. 分离根上下文与DispatcherServlet上下文(推荐最佳实践)
你当前把所有配置文件(包括Spring Security、Spring MVC的)都放到了同一个XmlWebApplicationContext里,由ContextLoaderListener和DispatcherServlet共用。这在Spring 3.x可能没问题,但Spring 5.x更推荐分离:
- 根上下文(ContextLoaderListener)加载:
applicationContext.xml、spring-security-db.xml(业务、安全相关配置) - DispatcherServlet上下文加载:
dispatcher-servlet.xml、doc-views.xml(MVC、视图相关配置)
修改你的onStartup方法:
@Override public void onStartup(ServletContext container) throws ServletException { // 根上下文:加载安全、业务配置 XmlWebApplicationContext rootContext = new XmlWebApplicationContext(); rootContext.setConfigLocations("/WEB-INF/****/applicationContext.xml","/WEB-INF/*****/spring-security-db.xml"); container.addListener(new ContextLoaderListener(rootContext)); // MVC上下文:加载MVC、视图配置 XmlWebApplicationContext dispatcherContext = new XmlWebApplicationContext(); dispatcherContext.setConfigLocations("/WEB-INF/***/dispatcher-servlet.xml","/WEB-INF/***/doc-views.xml"); dispatcherContext.setParent(rootContext); // 设置父上下文为根上下文 container.addListener(new HttpSessionEventPublisher()); container.addListener(new DriverRegistrationListener()); // Spring Security过滤器:默认从根上下文获取chain DelegatingFilterProxy delegatingFilterProxy = container.createFilter(DelegatingFilterProxy.class); container.addFilter("springSecurityFilterChain", delegatingFilterProxy).addMappingForUrlPatterns(null, false, "/*"); ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcher", new DispatcherServlet(dispatcherContext)); dispatcher.setLoadOnStartup(1); dispatcher.addMapping("/"); initalizeLog4j(container); }
这种分离方式能避免上下文混淆,减少Spring 5.x中因为上下文边界严格导致的问题。
4. 验证Spring Security登录页的权限配置
确保你的Spring Security配置中,登录页路径是允许匿名访问的,比如:
<security:http auto-config="true" use-expressions="true"> <!-- 允许登录页匿名访问 --> <security:intercept-url pattern="/login" access="permitAll()"/> <!-- 其他权限配置 --> <security:form-login login-page="/login" /> <!-- 你的自定义过滤器配置 --> <security:custom-filter after="BASIC_AUTH_FILTER" ref="securityFilters" /> </security:http>
如果登录页被拦截,Spring Security可能会返回空响应而不是重定向/渲染页面。
按照上面的步骤排查,应该能解决登录页返回空内容的问题。
内容的提问来源于stack exchange,提问作者guru mani

