403错误源于WebSocket握手被拦截,核心是Origin校验、代理头转发与Spring Security放行未对齐;需同时配置setAllowedOrigins指定源、Security显式放行端点路径(如/ws/**)、Nginx透传Upgrade头。

403 错误不是权限不足,而是 WebSocket 握手阶段被拦截或拒绝——核心在 Origin 校验、代理头转发、Spring Security 放行三处没对齐。
Spring Boot 原生 WebSocket 的 setAllowedOrigins 配置失效?
常见现象是加了 setAllowedOrigins("*") 仍报 403,尤其在 Spring Boot 2.6+ 或整合了 Spring Security 后。原因在于:该方法只控制握手请求的 Origin 头校验,但若 Spring Security 拦截了 /websocket 路径本身,根本不会走到握手逻辑。
- 必须确保
WebSocketHandlerRegistry注册的 endpoint 路径(如/ws)被 Spring Security 显式放行,否则 403 是 Security 返回的,不是 WebSocket 层的 -
setAllowedOrigins("*")在新版中已不推荐;改用setAllowedOrigins("https://your-domain.com", "http://localhost:3000")更安全,避免空字符串或通配符被忽略 - 若用 JWT 握手拦截器(
HandshakeInterceptor),务必在beforeHandshake中手动设置响应头:response.getHeaders().setAccessControlAllowCredentials(true),否则带withCredentials: true的前端会失败
Nginx 反向代理下 WebSocket 返回 403,不是跨域问题
错误日志里出现 Expected HTTP 101 response but was '403 Forbidden',基本可断定是 Nginx 没转发协议升级头,而非后端未配置跨域。
- 必须在
location块中显式添加:proxy_http_version 1.1、proxy_set_header Upgrade $http_upgrade、proxy_set_header Connection "upgrade" -
Connection头值必须是"upgrade"字面量(带双引号),不能写成$connection_upgrade变量而没定义映射,否则 Nginx 会传空值,触发 403 - 不要在 Nginx 层做
allowedOrigins控制——那是应用层的事;Nginx 只负责透传,否则容易和后端配置冲突
Spring Security + WebSocket 共存时的凭据与路径放行陷阱
当同时启用 Spring Security 和 WebSocket,且前端带 Cookie 连接时,403 往往源于两个响应头矛盾:Access-Control-Allow-Credentials: true 和 Access-Control-Allow-Origin: * 不能共存。
- Security 配置里必须关闭预检缓存:
.and().cors().configurationSource(request -> new CorsConfiguration().applyPermitDefaultValues()),否则预检响应可能漏掉凭据头 - WebSocket endpoint 路径(如
/ws/**)需单独放行:http.authorizeHttpRequests(authz -> authz.requestMatchers("/ws/**").permitAll()),不能只靠全局 CORS 配置 - 若使用 STOMP,还要额外放行
/ws/info(SockJS fallback 端点)和/topic/**等消息路径,否则首次连接就卡在 403
最易被忽略的是:WebSocket 握手请求(GET)和后续帧通信走的是同一条 TCP 连接,但 Spring Security 默认只检查初始 GET 的权限;一旦握手成功,后续 ping/pong 或消息帧不再经过 Security Filter Chain——所以路径放行必须在握手前完成,且不能依赖动态表达式(如 hasRole()),否则直接拒掉。


















