Spring STOMP添加CSRF令牌遇MissingCsrfTokenException报错求助
解决STOMP CONNECT时CSRF令牌验证失败(会话未找到)的问题
这个问题我之前帮好几个开发者排查过,核心原因是CSRF令牌和HttpSession的绑定时机不匹配——你在发送STOMP CONNECT帧的时候,对应的HttpSession还没在服务器端建立,导致Spring Security找不到令牌关联的会话,从而抛出MissingCsrfTokenException。
下面是具体的排查和解决步骤:
1. 先明确CSRF令牌的绑定逻辑
Spring Security的CSRF令牌是和HttpSession绑定存储的,默认会把令牌值通过XSRF-TOKEN Cookie返回给客户端(需要配置CookieCsrfTokenRepository.withHttpOnlyFalse()才能让前端读取)。如果客户端发送的令牌对应的会话不存在,服务器就会报错“会话未找到”。
2. 确保客户端发送CONNECT前已建立HttpSession
很多开发者犯的错是:页面加载后直接发起WebSocket连接+STOMP CONNECT,这时候还没有任何HTTP请求触发服务器创建HttpSession,导致令牌没有对应的会话。
解决方法:
- 在初始化STOMP客户端前,先发送一个简单的HTTP GET请求到服务器(比如访问一个静态资源或者空接口),触发会话创建。这个请求会让服务器把
XSRF-TOKENCookie返回给客户端,同时在服务器端创建会话并绑定令牌。
3. 检查客户端代码是否正确读取并传递令牌
以stomp.js为例,要确保正确读取Cookie中的XSRF-TOKEN,并放到CONNECT请求头里:
// 先获取Cookie中的XSRF令牌 function getCsrfToken() { const match = document.cookie.match(/XSRF-TOKEN=([^;]+)/); return match ? match[1] : null; } // 初始化STOMP客户端 const stompClient = new StompJs.Client({ brokerURL: 'ws://localhost:8080/ws', connectHeaders: { 'XSRF-TOKEN': getCsrfToken() }, // 其他配置... }); // 注意:先发起HTTP请求创建会话,再调用connect fetch('/api/init-session') // 这个接口可以是空实现,只要触发会话创建 .then(() => stompClient.connect());
4. 服务器端配置确认
Spring Security配置
确保CSRF令牌仓库配置正确,允许前端读取Cookie:
@Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .csrf(csrf -> csrf .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) ) .authorizeHttpRequests(auth -> auth .requestMatchers("/ws/**").permitAll() // WebSocket握手端点允许匿名访问 .anyRequest().authenticated() ) // 其他配置... return http.build(); }
WebSocket配置
不需要额外关闭CSRF,Spring Security会自动处理STOMP帧的CSRF验证:
@Configuration @EnableWebSocketMessageBroker public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { @Override public void configureMessageBroker(MessageBrokerRegistry config) { config.enableSimpleBroker("/topic"); config.setApplicationDestinationPrefixes("/app"); } @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/ws").withSockJS(); } }
5. 额外排查点
- 检查浏览器控制台的Cookie,确认
XSRF-TOKEN存在且值正确传递到了CONNECT头中; - 确保服务器端没有禁用HttpSession(比如设置
sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)会导致会话无法创建,这时候CSRF验证必然失败); - 如果你用的是分布式环境,要确保HttpSession能被正确共享(比如用Redis存储会话),否则不同节点可能找不到令牌对应的会话。
内容的提问来源于stack exchange,提问作者gstackoverflow
相关产品推荐
相关产品推荐

