Как сообщить клиенту websocket, что аутентификация не удалась - PullRequest
0 голосов
/ 22 апреля 2020

Я использую ( пакет ws ) для обслуживания веб-сокетов от Node.js. Я использую событие «при обновлении» для проверки подлинности подключающихся клиентов с использованием токена, переданного в качестве параметра URL. Следуя примеру здесь , в случае, если токен недействителен / отсутствует / истек, я использую следующий (машинописный) код для отклонения соединения:

server.on('upgrade', async (req: Request, socket: Socket) => {
  // Make sure that we only handle WebSocket upgrade requests
  if (req.headers['upgrade'] !== 'websocket') {
    socket.destroy(new Error(`Expected headers upgrade == 'websocket', received ${req.headers['upgrade']}`));
    return;
  }
  if (_.get(this.config, 'security.enableAuth')) {
    logger.info('[socket] security: validating the session key parameter');
    const u = querystring.parse(req.url.substring(req.url.indexOf('?') + 1));
    if (!u.sessionKey) {
      logger.info('[debug] no session key found');
      socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n');
      socket.destroy();
      return;
    }
    const token = u.sessionKey as string;
    let result: AuthResult;
    try {
      result = await auth(token);
    } catch (err) {
      logger.warn('[socket] error validating session key:', err);
      socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n');
      socket.destroy();
      return;
    }
    // and so on...

Это все работает, кроме как на стороне клиента, я не получаю сообщение 401 и ничего, что может сказать мне, почему не удалось установить соединение. Chrome вкладка сети показывает отсутствие полученных сообщений, а событие закрытия имеет код 1006 (CLOSE_ABNORMAL) без какой-либо другой информации. Как передать разумный код ошибки или сообщение, чтобы клиент знал, почему произошел сбой?

1 Ответ

0 голосов
/ 29 апреля 2020

Кажется, что обработка ответа 401 на стороне браузера невозможна, как это ни странно. Это делает «рекомендуемый» метод, используемый в вопросе, довольно ограниченным в применимости, так как нет никакого способа сообщить клиенту, почему рукопожатие было отклонено. Любые данные, записанные в сокет tcp, просто выбрасываются в браузер (хотя я думаю, что другой клиент может использовать их). В моем случае это ограничение нарушает условия сделки. Вместо того чтобы отказаться от рукопожатия, я принимаю его, а затем немедленно закрываю сокет с подходящим кодом и причиной:

this.wss.on('connection', async (ws: ExtendedWebSocket, req: Request) => {
logger.info('[socket] security: validating the session key parameter');
const u = querystring.parse(req.url.substring(req.url.indexOf('?') + 1));
if (!u.sessionKey) {
  logger.info('[debug] no session key found');
  ws.close(WS_CLOSE_CODES.CLOSE_POLICY_VIOLATION, 'Unauthorized'); // code=108
  return;
}
const token = u.sessionKey as string;
const result = await auth(token);
if (result.failed) {
  logger.warn(`[socket] invalid token (${token}) - auth failed`);
  ws.close(WS_CLOSE_CODES.CLOSE_POLICY_VIOLATION, 'Unauthorized');
  return;
}
// and so on...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...