websocket安全鉴权必须在握手阶段完成,推荐url传token(需https+短期有效)、复用sec-websocket-protocol字段(base64url编码)或反向代理注入authorization头,且token须短期有效、支持吊销、避免localstorage存储。

WebSocket 安全鉴权必须在握手阶段完成,不能等 onopen 触发后再发 Token——因为连接一旦升级,TCP 通道已就绪,服务端无法真正拒绝未授权连接,只能被动关闭,资源早已被占用。
推荐方案:URL 参数传 Token(开发快、兼容强)
这是最直接、浏览器原生支持最好的方式:
- 前端用
encodeURIComponent()编码 Token,拼入 URL 查询参数:const socket = new WebSocket(`wss://api.example.com/ws?token=${encodeURIComponent(token)}`); - 服务端从握手请求的
request.url或request.query中提取并校验,无效则返回 HTTP 401,连接根本不会升级 - 适合内部系统、调试工具或短期 Token 场景;但注意:Token 会出现在 Nginx/Apache 访问日志、浏览器地址栏和历史记录中,生产环境需搭配 HTTPS + 短期有效 Token(如 ≤30 分钟)
更安全方案:复用 Sec-WebSocket-Protocol 字段
该字段本用于子协议协商(如 ["chat-v2"]),但可“借用”传递 Token:
- 前端写法:
new WebSocket("wss://api.example.com/ws", ["Bearer eyJhbGci..."]) - 服务端读取
req.headers['sec-websocket-protocol'],提取并校验 Bearer 后的值 - 优势是 Token 不暴露在 URL 或日志中,且无需反向代理配合;限制是值只允许字母、数字、短横线和点,需确保 JWT 去掉
+、/、=等字符(可用 Base64Url 编码)
生产级方案:反向代理注入 Authorization 头
让前端保持干净 URL,由 Nginx/Traefik 在握手请求中注入认证头:
- Nginx 配置示例:
proxy_set_header Authorization "Bearer $arg_token";
或从 Cookie 提取:proxy_set_header Authorization "Bearer $cookie_auth_token"; - 后端可像处理普通 HTTP 请求一样,统一从
Authorization头读取并校验,与 REST API 完全一致 - 需要运维配合,但安全性高、逻辑清晰、便于审计,适合中大型项目
关键安全细节不能漏
无论选哪种传输方式,以下三点必须落实:
-
Token 必须短期有效:不复用登录接口返回的长期 JWT;应调用专用接口(如
/api/v1/ws-token)获取,exp ≤ 30 分钟,并响应头设Cache-Control: no-store - 必须支持主动吊销:握手时查 Redis 或数据库,确认 Token 未被用户登出或管理员踢出
- 主登录态优先用 httpOnly Cookie,WS Token 尽量内存暂存、用完即弃;避免存在 localStorage,防止 XSS 直接盗取
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











