HTTP headers in Websockets client API

2019-01-01 06:55发布

Looks like it's easy to add custom HTTP headers to your websocket client with any HTTP header client which supports this, but I can't find how to do it with the JSON API.

Yet, it seems that there should be support these headers in the spec.

Anyone has a clue on how to achieve it?

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

Specifically, I need to be able to send an HTTP Authorization header.

8条回答
墨雨无痕
2楼-- · 2019-01-01 07:18

Technically, you will be sending these headers through the connect function before the protocol upgrade phase. This worked for me in a nodejs project:

var WebSocketClient = require('websocket').client;
var ws = new WebSocketClient();
ws.connect(url, '', headers);
查看更多
看风景的人
3楼-- · 2019-01-01 07:20

HTTP Authorization header problem can be addressed with the following:

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

Then, a proper Basic Authorization HTTP header will be set with the provided username and password. If you need Basic Authorization, then you're all set.


I want to use Bearer however, and I resorted to the following trick: I connect to the server as follows:

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

And when my code at the server side receives Basic Authorization header with non-empty username and empty password, then it interprets the username as a token.

查看更多
旧人旧事旧时光
4楼-- · 2019-01-01 07:21

Updated

Short answer: No, but basic auth works

Longer answer:

There is no method in the JavaScript WebSockets API for specifying additional headers for the client/browser to send. However the HTTP path ("GET /xyz"), basic auth header ("Authorization") and protocol header ("Sec-WebSocket-Protocol") can be specified in the WebSocket constructor.

The Authorization header is generated from the username and password (or just username) field of the WebSocket URI:

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

The above results in the following header with the string "username:password" base64 encoded:

Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=

I have tested basic auth in Chrome 55 and Firefox 50 and verified that the basic auth info is indeed negotiated with the server (this may not work in Safari).

The Sec-WebSocket-Protocol header (which is sometimes extended to be used in websocket specific authentication) is generated from the optional second argument to the WebSocket constructor:

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

The above results in the following headers:

Sec-WebSocket-Protocol: protocol

and

Sec-WebSocket-Protocol: protocol1, protocol2

Thanks to Dmitry Frank's for the basic auth answer

查看更多
看风景的人
5楼-- · 2019-01-01 07:23

More of an alternate solution, but all modern browsers send the domain cookies along with the connection, so using:

var authToken = 'R3YKZFKBVi';

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

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

End up with the request connection headers:

Cookie: X-Authorization=R3YKZFKBVi
查看更多
梦醉为红颜
6楼-- · 2019-01-01 07:23

You can not send custom header when you want to establish WebSockets connection using JavaScript WebSockets API. You can use Subprotocols headers by using the second WebSocket class constructor:

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

and then you can get the Subprotocols headers using Sec-WebSocket-Protocol key on the server.

There is also a limitation, your Subprotocols headers values can not contain a comma (,) !

查看更多
倾城一夜雪
7楼-- · 2019-01-01 07:25

Sending Authorization header is not possible.

Attaching a token query parameter is an option. However, in some circumstances, it may be undesirable to send your main login token in plain text as a query parameter because it is more opaque than using a header and will end up being logged whoknowswhere. If this raises security concerns for you, an alternative is to use a secondary JWT token just for the web socket stuff.

Create a REST endpoint for generating this JWT, which can of course only be accessed by users authenticated with your primary login token (transmitted via header). The web socket JWT can be configured differently than your login token, e.g. with a shorter timeout, so it's safer to send around as query param of your upgrade request.

Create a separate JwtAuthHandler for the same route you register the SockJS eventbusHandler on. Make sure your auth handler is registered first, so you can check the web socket token against your database (the JWT should be somehow linked to your user in the backend).

查看更多
登录 后发表回答