Websockets客户端API中的HTTP标头

时间:2010-12-05 21:04:47

标签: javascript http header websocket

看起来很容易使用任何支持此功能的HTTP头客户端向您的websocket客户端添加自定义HTTP标头,但我无法找到如何使用JSON API执行此操作。

然而,似乎应该有支持these headers in the spec

任何人都知道如何实现它?

var ws = new WebSocket("ws://example.com/service");

具体来说,我需要能够发送HTTP授权标头。

12 个答案:

答案 0 :(得分:159)

更新了2次

简答:不,只能指定路径和协议字段。

更长的答案:

JavaScript WebSockets API中没有方法可以指定要发送的客户端/浏览器的其他标头。可以在WebSocket构造函数中指定HTTP路径(“GET / xyz”)和协议头(“Sec-WebSocket-Protocol”)。

从WebSocket构造函数的可选第二个参数生成Sec-WebSocket-Protocol标头(有时扩展为在websocket特定的认证中使用):

var ws = new WebSocket("ws://example.com/path", "protocol");
var ws = new WebSocket("ws://example.com/path", ["protocol1", "protocol2"]);

上述结果如下:

Sec-WebSocket-Protocol: protocol

Sec-WebSocket-Protocol: protocol1, protocol2

实现WebSocket身份验证/授权的一种常见模式是实现一个票证系统,其中托管WebSocket客户端的页面从服务器请求票证,然后在WebSocket连接设置期间在URL /查询字符串中传递此票证,协议字段,或在建立连接后作为第一条消息所需。然后,如果票证有效(存在,尚未使用,票证匹配中的客户端IP编码,票证中的时间戳是最近等),则服务器仅允许连接继续。以下是WebSocket安全信息的摘要:https://devcenter.heroku.com/articles/websocket-security

基本身份验证以前是一个选项,但已被弃用,现代浏览器即使指定了它也不会发送标头。

基本身份验证信息(已弃用)

Authorization标头是从WebSocket URI的用户名和密码(或只是用户名)字段生成的:

var ws = new WebSocket("ws://username:password@example.com")

上面的结果是以下标题,其中包含字符串“username:password”base64 encoded:

Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=

我已在Chrome 55和Firefox 50中测试了基本身份验证,并确认基本身份验证信息确实已与服务器协商(这可能无法在Safari中使用)。

感谢Dmitry Frank的基本身份验证answer

答案 1 :(得分:30)

HTTP授权标头问题可通过以下方式解决:

var ws = new WebSocket("ws://username:password@example.com/service");

然后,将使用提供的usernamepassword设置正确的基本授权HTTP标头。如果您需要基本授权,那么您已全部设置。

我想使用Bearer,然后我采用了以下技巧:我按如下方式连接到服务器:

var ws = new WebSocket("ws://my_token@example.com/service");

当我在服务器端的代码收到带有非空用户名和空密码的Basic Authorization标头时,它会将用户名解释为令牌。

答案 2 :(得分:17)

更多的替代解决方案,但所有现代浏览器都会将域cookie与连接一起发送,因此使用:

var authToken = 'R3YKZFKBVi';

document.cookie = 'X-Authorization=' + authToken + '; path=/';

var ws = new WebSocket(
    'wss://localhost:9000/wss/'
);

以请求连接标头结束:

Cookie: X-Authorization=R3YKZFKBVi

答案 3 :(得分:14)

您无法添加标题,但是,如果您只需要在连接时将值传递给服务器,则可以在网址上指定查询字符串部分:

var ws = new WebSocket("ws://example.com/service?key1=value1&key2=value2");

该URL有效但当然 - 您需要修改服务器代码以解析它。

答案 4 :(得分:12)

如果要使用JavaScript WebSockets API建立WebSockets连接,则无法发送自定义标头。 您可以使用第二个WebSocket类构造函数来使用Subprotocols标头:

var ws = new WebSocket("ws://example.com/service", "soap");

然后您可以使用服务器上的Sec-WebSocket-Protocol密钥获取子协议标头。

还有一个限制,您的子协议标头值不能包含逗号(,)!

答案 5 :(得分:2)

无法发送授权标头。

附加令牌查询参数是一种选择。但是,在某些情况下,可能不希望以纯文本形式将主登录令牌作为查询参数发送,因为它比使用标头更不透明,并且最终会被记录在任何地方。如果这给您带来了安全隐患,则另一种选择是仅将辅助JWT令牌用于Web套接字内容

创建一个用于生成此JWT的REST端点,当然,只有使用您的主要登录令牌(通过标头传输)进行身份验证的用户才能访问该端点。 Web套接字JWT的配置可以与您的登录令牌不同,例如超时时间较短,因此作为升级请求的查询参数发送出去比较安全。

为注册SockJS eventbusHandler的同一路由创建一个单独的JwtAuthHandler 。确保首先注册了身份验证处理程序,以便您可以针对数据库检查Web套接字令牌(JWT应该以某种方式链接到后端的用户)。

答案 6 :(得分:2)

在我的情况下(Azure时间序列见解wss://)

使用ReconnectingWebsocket包装器,并能够通过简单的解决方案添加标头:

socket.onopen = function(e) {
    socket.send(payload);
};

在这种情况下有效负载为:

{
  "headers": {
    "Authorization": "Bearer TOKEN",
    "x-ms-client-request-id": "CLIENT_ID"
}, 
"content": {
  "searchSpan": {
    "from": "UTCDATETIME",
    "to": "UTCDATETIME"
  },
"top": {
  "sort": [
    {
      "input": {"builtInProperty": "$ts"},
      "order": "Asc"
    }], 
"count": 1000
}}}

答案 7 :(得分:1)

完全是这样的,这要归功于kanaka的答案。

客户端:

var ws = new WebSocket(
    'ws://localhost:8080/connect/' + this.state.room.id, 
    store('token') || cookie('token') 
);

服务器(在此示例中使用Koa2,但在任何地方都应该类似):

var url = ctx.websocket.upgradeReq.url; // can use to get url/query params
var authToken = ctx.websocket.upgradeReq.headers['sec-websocket-protocol'];
// Can then decode the auth token and do any session/user stuff...

答案 8 :(得分:0)

我的案子:

  • 我想将www.mycompany.com/api/ws ...
  • 连接到生产WS服务器
  • 使用真实凭据(会话cookie)...
  • 从本地页面(localhost:8000)。

设置document.cookie = "sessionid=foobar;path=/"不会帮助您,因为域名不匹配。

解决方案

127.0.0.1 wsdev.company.com添加到/etc/hosts

这样,当您从有效的子域mycompany.com连接时,浏览器在连接到www.mycompany.com/api/ws时将使用wsdev.company.com的cookie。

答案 9 :(得分:0)

致所有未来的调试器 - 直到今天,即 15-07-21

浏览器也不支持向服务器发送客户标头,因此任何此类代码

    import * as sock from 'websocket'
    const headers = {
        Authorization: "bearer " + token
    };
    console.log(headers);

    const wsclient = new sock.w3cwebsocket(
        'wss://' + 'myserver.com' + '/api/ws',
        '',
        '',
        headers,
        null
    );

这在浏览器中不起作用。这背后的原因是浏览器原生 Websocket 构造函数不接受标头。

你很容易被误导,因为 w3cwebsocket 承包商接受我上面显示的标题。然而,这在 node.js 中有效。

答案 10 :(得分:-1)

从技术上讲,您将在协议升级阶段之前通过connect函数发送这些标头。这在nodejs项目中对我有用:

var WebSocketClient = require('websocket').client;
var ws = new WebSocketClient();
ws.connect(url, '', headers);

答案 11 :(得分:-2)

您可以将标题作为键值在对象内部的第三个参数(选项)中传递。 具有授权令牌的示例。将协议(第二个参数)留为空


ws = new WebSocket(‘ws://localhost’, null, { headers: { Authorization: token }})