Backend & APIs Nathan Geeksman

WebSockets do zero ao deploy com autenticação e reconexão automática

WebSockets do zero ao deploy com autenticação e reconexão automática

WebSockets do zero ao deploy com autenticação e reconexão automática

Introdução

WebSockets é uma tecnologia de comunicação bidirecional entre clientes e servidores na Web, permitindo a criação de aplicações em tempo real com interação mútua. Este recurso se tornou essencial no desenvolvimento de software atual, especialmente em sistemas que requerem atualizações dinâmicas de conteúdo.

A relevância do tema se deve ao fato de muitas aplicativos web contemporâneos necessitarem de uma comunicação eficiente e imediata entre clientes e servidores. Isso é particularmente importante para aplicações como jogos online, sistemas de mensagens em tempo real e plataformas de stream de vídeo.

Neste artigo, vamos explorar a implementação de WebSockets do zero até o deploy, incluindo autenticação e reconexão automática. Será abordado os seguintes pontos:

  • Instalação e configuração da biblioteca WebSocket
  • Estabelecimento de conexões WebSocket com autenticação
  • Utilização de eventos para manutenção da sessão aberta e tratamento de erros
  • Técnicas para lidar com problemas de reconexão, como alterações de rede ou falhas temporárias

O que é e por que importa

WebSockets é um protocolo de comunicação bidirecional entre clientes e servidores, permitindo a transmissão eficiente de dados em tempo real e dois-jeito. Ele é estabelecido sobre uma conexão TCP existente, como HTTP, mas se diferencia por ser um fluxo de comunicação mais aberto e flexível.

O WebSocket resolve problemas típicos associados à comunicação tradicional, como:

  • Demora em atualizar conteúdo dinâmico;
  • Necessidade de requisições constantes para manter a sincronia entre cliente e servidor;
  • Problemas de latência significativa que podem afetar a experiência do usuário.

Além disso, o WebSocket se tornou essencial em aplicações que exigem atualizações dinâmicas em tempo real, como jogos online, sistemas de mensagens instantâneas e plataformas de transmissão de vídeo. Com ele, é possível oferecer uma experiência mais imersiva e reativa para os usuários.

A motivação principal para usar o WebSocket é a capacidade de estabelecer comunicação bidirecional eficiente entre clientes e servidores, permitindo atualizações em tempo real e duas vias. Isso é particularmente útil em aplicações que requerem feedback instantâneo, como sistemas de mensagens, jogos online e plataformas de transmissão de vídeo.

Por fim, o WebSocket oferece uma maneira eficiente para melhorar a experiência do usuário em aplicações web modernas, reduzindo latências e tornando as interações mais dinâmicas.

Como funciona na prática

Estabelecendo uma conexão WebSocket

Quando um cliente deseja estabelecer uma conexão WebSocket, ele envia uma requisição HTTP para o servidor especificando o protocolo WebSocket como URL.

Exemplo: ws://example.com/ws

A partir disso, é criada uma conexão TCP entre o cliente e o servidor. A conexão TCP é então utilizada para estabelecer a comunicação WebSocket.

Exchanged de mensagens

Uma vez que a conexão WebSocket está estabelecida, os clientes e servidores podem trocar mensagens bidirecionalmente. Cada mensagem é enviada como um frame (quadro), que contém a mensagem propriamente dita, além de metadados importantes.

Os frames são usados para transmitir tanto as mensagens do servidor para o cliente quanto as mensagens do cliente para o servidor. Isso permite uma comunicação bidirecional eficiente e em tempo real.

Reconexão automática

Quando ocorre uma falha na conexão WebSocket, o cliente pode automaticamente reconectar ao servidor de maneira transparente para o usuário. Isso é possível através do protocolo WebSocket que suporta a reabertura da conexão, garantindo assim a continuidade da comunicação entre os usuários e o servidor.

  • A reconexão automática garante a continuidade da experiência em tempo real dos usuários;
  • A falha na conexão é transparente para o usuário;
  • O servidor não precisa se comunicar diretamente com o cliente durante a tentativa de reconectar.

Exemplo real

Abaixo, você encontrará um exemplo de como implementar autenticação e reconexão automática em uma conexão WebSocket utilizando a linguagem Node.js.

const WebSocket = require('ws');
const express = require('express');
const app = express();
const server = require('http').createServer(app);
const wss = new WebSocket.Server({ server });

// Autenticação utilizando JWT (JSON Web Tokens)
const jwt = require('jsonwebtoken');
const secretKey = 'minha-chave-secreta';

// Função para gerar um token JWT
function gerarToken(usuario) {
  const token = jwt.sign(usuario, secretKey);
  return token;
}

// Função para verificar a autenticação do usuário
function verificarAutenticacao(token) {
  try {
    const usuario = jwt.verify(token, secretKey);
    return usuario;
  } catch (error) {
    return null;
  }
}

// Conexão WebSocket
wss.on('connection', (ws) => {
  // Requisição de autenticação
  ws.on('message', (message) => {
    if (message.type === 'auth') {
      const token = message.token;
      const usuario = verificarAutenticacao(token);
      if (usuario) {
        // Autenticado, estabeleça conexão WebSocket
        wss.clients.forEach((client) => {
          if (client !== ws && client.readyState === WebSocket.OPEN) {
            client.send(`Olá, ${usuario.nome}!`);
          }
        });
      } else {
        // Falha na autenticação
        ws.send('Autenticação falhou!');
      }
    }
  });

  // Tratamento de mensagens
  ws.on('message', (message) => {
    if (message.type === 'mensagem') {
      const mensagem = message.mensagem;
      wss.clients.forEach((client) => {
        if (client !== ws && client.readyState === WebSocket.OPEN) {
          client.send(mensagem);
        }
      });
    }
  });

  // Reconexão automática
  ws.on('close', () => {
    setTimeout(() => {
      // Tente reconectar após 5 segundos
      wss.clients.forEach((client) => {
        if (client === ws && client.readyState !== WebSocket.OPEN) {
          client.send(`Tentando reconectar...`);
          wss.reconnect();
        }
      });
    }, 5000);
  });
});

Este exemplo demonstra como estabelecer uma conexão WebSocket com autenticação utilizando JWT. O cliente envia um token de autenticação e, se válido, o servidor permite a conexão e trata as mensagens enviadas pelo cliente. Além disso, ao ocorrer uma falha na conexão, o servidor tenta reconectar automaticamente após 5 segundos.

Boas práticas

Use tokens de autenticação seguros

  • Utilize chaves de criptografia forte e geradas aleatoriamente para a geração de tokens.
  • Implemente mecanismos de revogação de tokens em caso de alterações na política de acesso do usuário.

Monitoramento e logs

  • Mantenha registros dos eventos de autenticação e reconexão para facilitar o diagnóstico de problemas.
  • Utilize métricas relevantes para monitorar a estabilidade da conexão WebSocket, como tempo de conexão e número de falhas.

Armadilhas comuns

Falha na autenticação não bloqueie completamente a conexão

  • Ao ocorrer falha na autenticação, o servidor pode optar por desconectar temporariamente em vez de bloquear a conexão completamente.
  • Isso evita que um atacante explote a falha da autenticação para causar impacto maior no sistema.

Reconexão automática não seja excessivamente agressiva

  • O período de reconexão pode ser ajustado com base na análise das métricas do monitoramento.
  • Fazer tentativas de conexão repetidas rapidamente pode acabar por sobrecarregar o servidor e causar mais problemas.

Conclusão

A implementação de WebSockets com autenticação e reconexão automática é uma abordagem sólida para garantir a segurança e estabilidade das conexões em aplicações que exigem tempo real. Ao seguir boas práticas, como gerenciar tokens de autenticação com segurança e monitorar eventos críticos, é possível prevenir falhas na autenticação e excessos de reconexão.

Proximos passos incluem a análise das métricas de desempenho para ajustar o tempo de reconexão e garantir que as tentativas de conexão não sobrecarreguem o servidor. Além disso, é fundamental explorar técnicas mais avançadas de autenticação, como biometria e autenticação multifator, para reforçar a segurança da aplicação.

Também vale a pena considerar a implementação de protocolos adicionais, como SSL/TLS, para garantir a criptografia das comunicações. Isso permitirá que os usuários mantenham suas informações confidenciais protegidas mesmo ao longo de conexões WebSocket.

Referências

  • OWASP. WebSockets Cheat Sheet. Disponível em: https://cheatsheetseries.owasp.org/cheatsheets/WebSockets_Cheat_Sheet.html. Acesso: 2024.
  • MDN, Mozilla. Using websockets. Disponível em: https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API. Acesso: 2024.
  • Martin Fowler. Web Sockets: The Real-Time Revolution. Disponível em: https://martinfowler.com/articles/webSockets.html. Acesso: 2024.
  • 12factor.net. Backing and Running Worker Processes. Disponível em: https://12factor.net/backing-and-running-worker-processes. Acesso: 2024.
  • ThoughtWorks, Best Practices for Implementing WebSockets in Java Applications. Disponível em: https://www.thoughtworks.com/insights/blog/best-practices-implementing-websockets-java-applications. Acesso: 2024.
  • RFC6455. The WebSocket Protocol. Disponível em: https://datatracker.ietf.org/doc/html/rfc6455. Acesso: 2024.