SpringBoot 3适配带点前缀旧Cookie配置的问题与方案问询
我们有一个以MS Azure作为SSO认证提供商的认证微服务,当前基于SpringBoot 2.7开发,需要升级至SpringBoot 3.x版本。
核心问题:用户认证时,浏览器会生成以“.”开头的JSESSIONID Cookie(例如.domain.name),原本依赖Tomcat的LegacyCookieProcessor来处理这类Cookie(符合旧版Tomcat Cookie域名验证规则),但Tomcat 10.1已移除该处理器,升级SpringBoot 3后应用报错无效Cookie域名。
已尝试的方案
- 方案1:升级SpringBoot至3.1.4,排除默认Tomcat Starter,手动引入Tomcat 10.0.27的
tomcat-embed相关依赖,同时引入jakarta.servlet-api6.0.0(否则测试时找不到jakarta.servlet.ServletConnection类) - 方案2:引入SpringBoot 2.7.16版本的
spring-boot-starter-tomcat(对应Tomcat 9.x)
两种方案下服务器均可正常启动,但调用/logout接口时客户端返回404,控制器未被触发。
待解决问题
- 上述配置中存在什么问题?
- 在SpringBoot 3中是否有其他方式处理带点前缀的旧域名Cookie?
针对问题1:现有配置的问题
方案1的问题
SpringBoot 3.1.x官方适配Tomcat 10.1.x版本,强行降级到Tomcat 10.0.27会引发依赖兼容性冲突:
- Tomcat 10.0.x对应Jakarta Servlet 5.0,而SpringBoot 3.x依赖Jakarta Servlet 6.0,手动引入的
jakarta.servlet-api6.0.0与Tomcat 10.0.x内置的Servlet API版本冲突,破坏Spring MVC请求映射逻辑,导致/logout控制器无法被正确识别。 - SpringBoot自动配置逻辑基于对应版本Tomcat设计,强行替换Tomcat版本会打断自动配置链,比如安全认证相关的过滤器、拦截器未正确注册,最终引发接口404。
方案2的问题
SpringBoot 3.x与2.7.x的Tomcat Starter完全不兼容:
- SpringBoot 2.7.x基于Jakarta EE 8(Servlet API 4.0,包名
javax.servlet),SpringBoot 3.x基于Jakarta EE 9+(Servlet API 6.0,包名jakarta.servlet),强行引入旧版Tomcat Starter会导致大量类路径冲突,服务器虽能启动,但Spring MVC请求处理链已损坏,/logout接口无法被正常路由。
针对问题2:SpringBoot 3中处理带点前缀Cookie的替代方案
1. 自定义CookieProcessor
Tomcat 10.1.x移除LegacyCookieProcessor后,可通过自定义CookieProcessor兼容带点前缀的域名:
import org.apache.tomcat.util.http.Rfc6265CookieProcessor; import org.apache.tomcat.util.http.SameSiteCookies; import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.server.WebServerFactoryCustomizer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class TomcatCookieConfig { @Bean public WebServerFactoryCustomizer<TomcatServletWebServerFactory> cookieProcessorCustomizer() { return factory -> { factory.addContextCustomizers(context -> { Rfc6265CookieProcessor cookieProcessor = new Rfc6265CookieProcessor(); // 自定义域名匹配规则,允许以.开头的旧格式域名 cookieProcessor.setDomainPattern("^\\.?([a-zA-Z0-9-]+\\.)+[a-zA-Z0-9-]+$"); cookieProcessor.setSameSiteCookies(SameSiteCookies.LAX); context.setCookieProcessor(cookieProcessor); }); }; } }
该配置通过扩展Rfc6265CookieProcessor,修改域名验证规则,允许带点前缀的Cookie域名通过校验。
2. 调整Spring Security的Cookie配置
如果是Spring Security管理的认证Cookie或JSESSIONID,可直接在Security配置中指定Cookie域名,绕过Tomcat的验证:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.web.SecurityFilterChain; @Configuration public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth.anyRequest().authenticated()) .oauth2Login() .and() .logout(logout -> logout .logoutUrl("/logout") .deleteCookies("JSESSIONID") // 直接指定兼容旧格式的Cookie域名 .cookieClearingLogoutHandler(cookie -> cookie.setCookieDomain(".domain.name")) ); return http.build(); } }
通过直接配置Cookie域名,让Spring Security生成符合要求的Cookie,同时处理注销时的Cookie清理,避免Tomcat的验证拦截。
3. 逐步迁移到标准Cookie域名格式
长远来看,建议逐步替换旧的.domain.name格式为标准的domain.name(不带前缀点):
- 现代浏览器均支持不带前缀点的顶级域名Cookie,可通过灰度发布逐步切换Cookie域名格式,最终移除对旧格式的依赖,彻底兼容Tomcat 10.1.x及SpringBoot 3.x。
内容的提问来源于stack exchange,提问作者Nestor Milyaev

