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