看起来很容易使用任何支持此功能的HTTP头客户端向您的websocket客户端添加自定义HTTP标头,但我无法找到如何使用JSON API执行此操作。
然而,似乎应该有支持these headers in the spec。
任何人都知道如何实现它?
var ws = new WebSocket("ws://example.com/service");
具体来说,我需要能够发送HTTP授权标头。
答案 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");
然后,将使用提供的username
和password
设置正确的基本授权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
... 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 }})