You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Security下STOMP使用:stompjs带Token连接遇401问题

在Spring Security环境下使用STOMP携带Token认证的解决方案

你当前的stompjs代码存在参数传递错误,导致Authorization头未被正确添加到STOMP CONNECT帧中,另外需要区分WebSocket握手阶段的请求头和STOMP协议帧的头信息,两者处理方式不同,以下是具体解决步骤:

1. 修正stompjs的connect参数写法

你的代码错误地将headers嵌套在headers字段中,stompjs的connect方法第一个参数直接接收头信息对象,无需额外嵌套:

// 修正后的代码
let client = Stomp.client("ws://192.168.181.77:3001/ws");
client.connect(
  {
    Authorization: "Bearer TOKEN" // 直接传递头信息,不要嵌套在headers里
  },
  () => {
    console.log("client ok");
  },
  () => {
    console.log("client not ok");
  }
);

2. 处理WebSocket握手阶段的认证(若Spring Security在握手时校验)

如果你的Spring Security是在WebSocket握手请求阶段就校验Token(而非STOMP CONNECT帧),需要在创建WebSocket连接时设置请求头,此时不能用Stomp.client,需手动创建WebSocket实例并添加头:

// 手动创建带请求头的WebSocket
const socket = new WebSocket("ws://192.168.181.77:3001/ws", {
  headers: {
    Authorization: "Bearer TOKEN"
  }
});

// 基于这个WebSocket创建Stomp客户端
let client = Stomp.over(socket);

client.connect(
  {}, // 握手阶段已传Token,这里可空或补充其他STOMP帧头
  () => {
    console.log("client ok");
  },
  () => {
    console.log("client not ok");
  }
);

3. Spring Security端的配置调整

3.1 放行WebSocket端点

确保SecurityFilterChain中放行你的WebSocket端点(/ws),允许OPTIONS预检请求和携带Authorization头:

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
        .authorizeHttpRequests(auth -> auth
            .requestMatchers("/ws/**").permitAll() // 放行WebSocket端点
            .anyRequest().authenticated()
        )
        .csrf(csrf -> csrf
            .ignoringRequestMatchers("/ws/**") // WebSocket无需CSRF校验
        );
    return http.build();
}

3.2 配置STOMP帧认证(若在STOMP帧中校验)

如果是在STOMP CONNECT帧中校验Token,需配置ChannelInterceptor提取帧中的Authorization头并完成认证:

@Component
public class StompAuthInterceptor implements ChannelInterceptor {

    private final AuthenticationManager authenticationManager;

    public StompAuthInterceptor(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
    }

    @Override
    public Message<?> preSend(Message<?> message, MessageChannel channel) {
        StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);
        if (StompCommand.CONNECT.equals(accessor.getCommand())) {
            String authHeader = accessor.getFirstNativeHeader("Authorization");
            if (authHeader != null && authHeader.startsWith("Bearer ")) {
                String token = authHeader.substring(7);
                // 替换为你的Token解析逻辑,创建Authentication对象
                Authentication authentication = new UsernamePasswordAuthenticationToken(token, token);
                Authentication authenticated = authenticationManager.authenticate(authentication);
                SecurityContextHolder.getContext().setAuthentication(authenticated);
            }
        }
        return message;
    }
}

然后在WebSocket配置中注册该拦截器:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    private final StompAuthInterceptor stompAuthInterceptor;

    public WebSocketConfig(StompAuthInterceptor stompAuthInterceptor) {
        this.stompAuthInterceptor = stompAuthInterceptor;
    }

    @Override
    public void configureClientInboundChannel(ChannelRegistration registration) {
        registration.interceptors(stompAuthInterceptor);
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/topic");
        config.setApplicationDestinationPrefixes("/app");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/ws").withSockJS(); // 若使用SockJS则添加此配置
    }
}

关键注意点

  • 区分WebSocket握手请求(HTTP请求)和STOMP协议帧:前者是建立WebSocket连接的HTTP请求,后者是连接建立后发送的STOMP消息帧,两者头信息设置方式不同。
  • 若使用SockJS,由于其可能降级为XHR等传输方式,手动设置WebSocket头的方式可能失效,此时建议将Token作为查询参数传递(如ws://192.168.181.77:3001/ws?token=xxx),再在Spring端的握手拦截器中提取查询参数完成认证。

内容的提问来源于stack exchange,提问作者Senith Uthsara

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 20:17:20