HTTP-заголовки в API-интерфейсах Websockets

Похоже, что добавлять пользовательские заголовки HTTP к клиенту websocket с помощью любого HTTP-заголовка, который поддерживает это, но я не могу найти, как это сделать с помощью JSON API.

Тем не менее, похоже, что в заголовке спецификации

В частности, мне нужно иметь возможность отправлять заголовок HTTP-авторизации.

Ответ 1

Обновлено 2 раза

Краткий ответ: Нет, можно указать только путь и поле протокола.

Более длинный ответ:

В JavaScript WebSockets API нет метода для указания дополнительных заголовков для клиента/браузера для отправки. Путь 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-адрес клиента закодирован в совпадениях с заявкой, timestamp в заявке недавно и т.д.). Вот краткая информация о безопасности WebSocket: https://devcenter.heroku.com/articles/websocket-security

Раньше базовая аутентификация была опцией, но она устарела, и современные браузеры не отправляют заголовок, даже если он указан.

Основная информация об аутентификации (устарела):

Заголовок авторизации создается из поля имени пользователя и пароля (или просто имени пользователя) URI WebSocket:

var ws = new WebSocket("ws://username:[email protected]")

Выше приведен следующий заголовок со строкой "username: password" в кодировке base64:

Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=

Я протестировал базовую аутентификацию в Chrome 55 и Firefox 50 и убедился, что базовая аутентификационная информация действительно согласовывается с сервером (это может не работать в Safari).

Спасибо Дмитрию Франку за базовый ответ .

Ответ 2

Проблема заголовка HTTP-авторизации может быть решена следующим образом:

var ws = new WebSocket("ws://username:[email protected]/service");

Затем соответствующий HTTP-заголовок Basic Authorization будет установлен с предоставленными username и password. Если вам нужна базовая авторизация, тогда вы все настроены.


Я хочу использовать Bearer, но я применил следующий трюк: я подключаюсь к серверу следующим образом:

var ws = new WebSocket("ws://[email protected]/service");

И когда мой код на стороне сервера получает заголовок Basic Authorization с непустым именем пользователя и пустым паролем, он интерпретирует имя пользователя как токен.

Ответ 3

Это скорее альтернативное решение, но все современные браузеры отправляют файлы cookie домена вместе с подключением, поэтому используйте:

var authToken = 'R3YKZFKBVi';

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

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

Получите заголовки соединения запроса:

Cookie: X-Authorization=R3YKZFKBVi

Ответ 4

Вы не можете добавлять заголовки, но если вам просто нужно передать значения на сервер в момент соединения, вы можете указать часть строки запроса на URL:

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

Этот URL-адрес действителен, но, конечно же, вам нужно будет изменить код сервера, чтобы проанализировать его.

Ответ 5

Вы не можете отправлять пользовательский заголовок, если хотите установить соединение WebSockets с помощью JavaScript WebSockets API. Вы можете использовать заголовки Subprotocols, используя второй конструктор класса WebSocket:

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

и затем вы можете получить заголовки подпротоколов, используя клавишу Sec-WebSocket-Protocol на сервере.

Существует также ограничение: значения заголовков ваших подпротоколов не могут содержать запятую (,)!

Ответ 6

Отправка заголовка авторизации невозможна.

Присоединение параметра запроса токена является опцией. Однако в некоторых случаях может быть нежелательно отправлять основной токен входа в виде обычного текста в качестве параметра запроса, поскольку он более непрозрачен, чем использование заголовка, и в конечном итоге будет зарегистрирован, кто знает где. Если это вызывает у вас проблемы с безопасностью, альтернативой является использование вторичного токена JWT только для веб-сокетов.

Создайте конечную точку REST для генерации этого JWT, к которому, конечно, могут обращаться только пользователи, аутентифицированные с помощью вашего основного токена входа (переданного через заголовок). Веб-сокет JWT может быть настроен иначе, чем ваш токен входа, например с более коротким тайм-аутом, поэтому безопаснее отправить его в качестве параметра запроса на обновление.

Создайте отдельный JwtAuthHandler для того же маршрута, который вы зарегистрировали в SockJS eventbusHandler в. Сначала убедитесь, что ваш обработчик аутентификации зарегистрирован, чтобы вы могли проверить токен веб-сокета в своей базе данных (JWT должен быть каким-то образом связан с вашим пользователем в бэкэнде).

Ответ 7

Полностью взломал его так, благодаря ответу Канаки.

Клиент:

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

Вы можете передать заголовки как значение ключа в третьем параметре (опции) внутри объекта. Пример с токеном авторизации. Оставил протокол (второй параметр) как ноль

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

Ответ 9

Технически вы будете отправлять эти заголовки через функцию соединения до фазы обновления протокола. Это сработало для меня в проекте nodejs:

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