如何告诉 websocket 客户端身份验证失败

see*_*per 6 authentication websocket node.js typescript

我正在使用(ws 包)从 Node.js 提供 websocket 服务。我使用“升级时”事件,使用作为 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...
Run Code Online (Sandbox Code Playgroud)

这一切都有效,除了在客户端我没有收到 401 消息,也没有任何可以告诉我连接失败原因的信息。Chrome 网络选项卡显示未收到消息,关闭事件的代码为 1006 (CLOSE_ABNORMAL),没有其他信息。如何传递合理的错误代码或消息以便客户端知道失败发生的原因?

see*_*per 5

看来 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...
Run Code Online (Sandbox Code Playgroud)