WebSocket 连接中使用 JWT Token 进行身份验证的正确实践

WebSocket 连接中使用 JWT Token 进行身份验证的正确实践

websocket 客户端需将 jwt token 通过 `authorization: bearer ` 请求头传递,而非 url 查询参数;go 服务端默认仅从 `authorization` 头或 `access_token` 表单字段解析 token,不支持直接读取查询参数。

在基于 WebSocket 的实时通信场景中,安全地完成用户身份鉴权至关重要。许多开发者误以为可通过 URL 查询参数(如 ?token=xxx 或 ?access_token=xxx)向 WebSocket 服务端传递 JWT,但实际中——尤其是使用 dgrijalva/jwt-go(现维护分支为 golang-jwt/jwt)等标准库进行解析时——服务端验证逻辑默认不解析查询参数中的 token

如问题中 Go 服务端代码所示,ParseFromRequest 函数仅检查两个位置:

  1. Authorization 请求头(格式为 Bearer );
  2. access_token 表单字段(需经 req.ParseMultipartForm() 或 req.ParseForm() 解析后的 req.Form)。

而 WebSocket 握手请求(HTTP Upgrade)不会自动将 URL 查询参数注入 req.Form,即使调用了 req.ParseMultipartForm(10e6),该方法也仅处理 multipart/form-data 类型的请求体(常见于文件上传),对 application/x-www-form-urlencoded 或纯 query string 无作用。因此 req.Form.Get(“access_token”) 始终为空,最终返回 ErrNoTokenInRequest。

✅ 正确做法:将 Token 放入 Authorization 请求头

白果AI论文

白果AI论文

论文AI生成学术工具,真实文献,免费不限次生成论文大纲 10 秒生成逻辑框架,10 分钟产出初稿,智能适配 80+学科。支持嵌入图表公式与合规文献引用

下载

使用 Python 客户端(如 websocket-client)时,应通过 header 参数显式传入认证头:

from websocket import create_connection

def test_auth_token(token):
    # ✅ 正确:通过 Header 传递 Bearer Token
    headers = ["Authorization: Bearer " + token]
    ws_url = f"ws://:port/{container.uuid}"

    conn = create_connection(ws_url, header=headers)
    result = conn.recv()
    assert result is not None
    conn.close()

⚠️ 注意事项:

  • Authorization 头值必须严格遵循 Bearer 格式(注意 Bearer 后有一个空格);
  • 确保 Token 未被 URL 编码(若手动拼接 URL,需避免对 token 二次编码;而 header 中无需编码);
  • 若服务端使用较新版本 golang-jwt/jwt/v5,建议升级并配合 http.Request.Context() 进行更健壮的 token 提取与验证;
  • 避免在 URL 中传递敏感 Token(易被日志、代理、浏览器历史记录泄露),Header 是更安全、符合规范的方式。

? 扩展建议:
服务端可增强兼容性,例如主动从 req.URL.Query().Get(“access_token”) 读取查询参数(需自行实现,非 jwt-go 默认行为)。但推荐客户端统一走 Header 方案,既符合 OAuth 2.0 / RFC 6750 规范,也便于与现有 HTTP API 鉴权逻辑保持一致。

https://www.php.cn/faq/1976461.html

发表回复

Your email address will not be published. Required fields are marked *