Como criar um servidor de WebSockets em Node.js - Parte 2

Node.js

Como criar um servidor de WebSockets em Node.js - Parte 2

Luiz Duarte
Escrito por Luiz Duarte em 22/07/2021
Junte-se a mais de 22 mil profissionais de TI

Entre para minha lista e receba conteúdos exclusivos e com prioridade

Na primeira parte desta série de tutoriais eu lhe mostrei como configurar um projeto Node.js que funcionasse tanto como web server (Express) quanto como um web sockets server (WS). Nesta segunda parte, vamos fazer com que nosso web socket server possa enviar mensagens para os clientes conectados além de aprender como colocar segurança nele.

Veremos:

  1. Enviando mensagens assíncronas
  2. Segurança em Servidor WS

Vamos lá!

Curso FullStack

#1 – Enviando mensagens assíncronas

Na lição anterior vimos como facilmente podemos mandar mensagens síncronas de volta para o websocket client. Mas e quando queremos mandar mensagens assíncronas, que é o grande “barato” de ter um websocket server? Neste caso, podemos implementar uma função de envio que pode ser disparada a qualquer momento e que não depende de recebermos qualquer comunicação do cliente.

Abaixo, uma implementação simples de função broadcast, que avisa todos os clientes conectados de alguma novidade.

Nesta função, se tiver clientes conectados vamos enviar uma mensagem para cada cliente com conexão aberta (OPEN). Você pode usar este exemplo de broadcast para criar outros tipos de lógicas para enviar a clientes específicos, desde que na conexão de cada cliente você guarde a identidade de cada um deles associado ao objeto ws presente no array this.clients.

Esta função será injetada no objeto wss o qual temos acesso lá na nossa index.js. No exemplo abaixo, vamos enviar uma mensagem aleatória a cada 1 segundo para todos clientes conectados, usando a função broadcast que criamos.

Agora, se você se conectar usando o Smart WebSocket Client se conectar no servidor, passará a receber um número aleatório a cada segundo, independente se tiver mandando uma mensagem para o servidor ou não (quando mandar mensagens receberá o “recebido” como resposta).

Repare que o broadcast envia para todos os clientes conectados e com conexão OPEN. Assim, um cliente que esteja desconectado, só passará a receber as mensagens depois de se conectar e somente as próximas mensagens, não existe gestão de histórico, algo que você pode implementar caso deseje usando filas com RabbitMQ ou AWS SQS por exemplo (clique nos links para tutoriais de filas em Node.js).

Curso Node.js e MongoDB

#2 – Segurança em Servidor WS

E se você estiver construindo um servidor de websockets profissional, certamente não irá querer deixar ele aberto pra todo mundo, certo? Por mais que o protocolo websockets seja bem leve, geralmente ficar enviando dados da sua aplicação para anônimas não costuma ser uma boa ideia, a menos que seu server seja exatamente para isso (como as streams de criptomoedas da Binance). Então como podemos implementar segurança em nosso websocket server?

Lembra que mencionei na primeira parte que usaríamos o websocket server integrado ao Express para ter alguns recursos a mais? Pois é, um deles é a rota de login. Hoje ela retorna um token sempre, mas ali você pode implementar a sua lógica de autenticação e só devolver o token (recomendo JWT) em caso de login com sucesso. Uma vez com este token recebido e armazenado no cliente, ele deverá ser usado para realizar uma conexão com seu servidor de websockets.

Vamos ver isso na prática!

Um servidor de websockets que deseja verificar a autenticidade de um cliente deve fazê-lo antes da conexão, no momento que chamamos de handshake em redes de computadores. Na biblioteca WS isso é implementado através de uma função verifyClient que deve ser passada logo na configuração do servidor e que será disparada ANTES de qualquer conexão ser estabelecida, em uma fase de autenticação mesmo.

Assim, na função verifyClient acima você tem acesso a um objeto info.req com todos os dados da requisição HTTP que acabou de chegar para o handshake e uma função de callback para dar uma resposta se o servidor irá ou não aceitar esta conexão. Uma vez que você aceite a conexão, passando true ao callback, esse verifyClient não será mais executado, mas sim o onConnection e mais tarde as demais funções onMessage e onError.

O céu é o limite no que tange o que você pode implementar nesta função verifyClient, mas aqui vai um exemplo simples que implementa uma lógica de CORS e de token para garantir que somente clientes da nossa origem válida (lembra que definimos ela no .env, na parte 1 do tutorial?) e que possuam um token válido é que podem prosseguir (você poderia usar validação de JWT aqui).

Repare que agora já temos alguma segurança embora mínima. Se você reiniciar o seu servidor e testar novamente com o Smart WebSocket Client verá que o botão de conexão parece não funcionar mais. Isso porque para poder se conectar, agora você tem de informar um token válido na querystring, como abaixo.

Aí sim, uma vez autenticado, você passará a receber os dados enviados pelo servidor WS e também poderá enviar mensagens para ele novamente.

E com isso finalizamos mais esta etapa. Neste outro tutorial eu vou lhe mostrar como você pode criar um cliente console para se comunicar com este servidor de websockets e neste aqui, um cliente web.

Até lá!

TAGS: nodejs

Olá, tudo bem?

O que você achou deste conteúdo? Conte nos comentários.