node.js - Hvordan fortelle websocket-klienten at autentisering mislyktes


Jeg bruker (ws-pakken) for å levere websockets fra Node.js. Jeg bruker "on upgrade"-hendelsen for å autentisere de tilkoblede klientene ved hjelp av en token som sendes som en URL-parameter. I følge eksemplet her, i tilfelle tokenet er ugyldig/mangler/utløpt, bruker jeg følgende (typescript)-kode for å avvise tilkoblingen:

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...

Dette fungerer alt sammen, bortsett fra at jeg på klientsiden ikke mottar 401-meldingen, eller noe som kan fortelle meg hvorfor tilkoblingen feilet. Chrome nettverksfane viser ingen mottatte meldinger, og close-hendelsen har kode 1006 (CLOSE_ABNORMAL), uten annen informasjon. Hvordan kan jeg sende en fornuftig feilkode eller melding slik at klienten vet hvorfor feilen oppstod?

Svar #1

Det ser ut til at det ikke er mulig å håndtere 401-responsen på browsersiden, så rart som det kan virke. Dette gjør at den "anbefalte" metoden som brukes i spørsmålet er ganske begrenset i anvendelighet, siden det ikke finnes noen måte å fortelle klienten hvorfor håndtrykket ble avvist. All data som skrives til tcp-socketen blir rett og slett kastet i nettleseren (selv om en annen klient kanskje kan bruke det, antar jeg). I mitt tilfelle er denne begrensningen en deal breaker. I stedet for å avvise håndtrykket, aksepterer jeg det, og lukker deretter umiddelbart socketen med en passende kode og årsak:

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...

Relaterte artikler