Sessões com NodeJS

Sessões com NodeJS

Em aulas passadas, você aprendeu a fazer a utilização de cookies para armazenar pequenas informações no navegador do seu usuário.

Só que a milhares de anos atrás, isto é, antes dos cookies serem implementados, só existia uma única forma de persistência de dados em um navegador, as sessões!

Hoje, você vai aprender tudo o que precisa saber sobre sessões de navegadores, e como criá-las usando uma aplicação bnack-end em conjunto com a biblioteca do Express.

Spoiler: sessões com NodeJS nada mais são do que cookies de duração mínima 🤫

Vamos nessa? 🙂

O que são sessões de navegador?

Uma sessão, é uma mecanismo presente na maioria dos navegadores de internet, cujo o objetivo é armazenar dados temporários que podem ser consumidos e criados por diferentes páginas.

Essas sessões, duram enquanto o usuário mantem o seu navegador aberto, ou seja, a partir do momento em que ele fecha o navegador, aquela informação será perdida.

Isso significa dizer, que uma sessão foi feita para o armazenamento de dados temporários, como itens de um carrinho de compras, histórico de navegação entre páginas, dados do usuário que está logado, preferências de idiomas e etc.

As sessões são consideradas "stateless", ou seja, que não mantêm o estado entre requisições HTTP.

Podemos dizer, que as sessões são consideradas mais seguras, uma vez que os dados sensíveis não são enviados em cada requisição, apenas o identificador de cada um deles.

No entanto, as sessões podem ser vulneráveis a ataques, como é o caso do roubo de sessão (session hijacking).

Diferente das sessões, os Cookies são mais indicados para persistir informações entre sessões, possuindo mais restrições quanto à segurança.

Dito isso, vamos aprender a criar sessões usando NodeJS + Express 🤓

Criando nosso projeto de testes

O projeto que iremos criar agora é bem simples, para isso, nós vamos instalar a biblioteca do Express, pois sem ela não iremos conseguir utilizar a biblioteca capaz de gerenciar nossas sessões 😉

Observação: o gerenciamento de sessões envolve exclusivamente o uso de uma biblioteca capaz de colocar um servidor online, e isso incluí o uso do módulo HTTP, ou de uma outra biblioteca especializada nisso, como é o caso do Express.

Dito isso, vamos começar criando uma nova pasta dedicada ao nosso projeto, no meu caso, eu criei uma pasta chamada de Sessoes dentro da minha área de trabalho (desktop):

Com o seu terminal (Prompt de Comando) aberto na pasta raiz que acabamos de criar, precisamos inicializar o nosso projeto por meio do NPM, sendo assim, execute o seguinte comando abaixo:

npm init -y

A flag -y, como você já deve saber, cria um novo projeto de forma enxuta, respondendo SIM para tudo 😅

Em seguida, vamos precisar instalar duas bibliotecas para o nosso projeto, o express e o express-session:

npm install express express-session

Será por meio da biblioteca do express-session que seremos capazes de criar um middleware em conjunto com Express, para o tratamento de sessões do navegador do usuário.

Feito isso, vamos criar dois pontos de entrada dentro da pasta raiz do nosso projeto:

  • index_http.js (aqui iremos demonstrar como gerenciar suas sessões usando o módulo HTTP),
  • index_express.js (aqui iremos demonstrar como gerenciar suas sessões usando o Express).

Gerenciando suas sessões com o módulo HTTP

O processo de gerenciamento de sessões utilizando o módulo HTTP, pode soar como uma tarefa um tanto quanto trabalhosa, vejamos como isso pode ser feito.

index_http.js:

const http = require('http');

// Simulação de um armazenamento de sessões em memória
let session = null;  // Inicialmente, nenhuma sessão

// Função para manipular as requisições e rotas
const server = http.createServer((req, res) => {
    if (req.url === '/criar' && req.method === 'GET') {
        // Criar sessão mockada
        session = { id: 1, nome: 'Usuário Sessão', status: 'Ativo' };
        res.writeHead(200, { 'Content-Type': 'text/plain' });
        res.end('Sessão criada com sucesso!');
    } else if (req.url === '/ler' && req.method === 'GET') {
        // Ler sessão mockada
        if (session) {
            res.writeHead(200, { 'Content-Type': 'application/json' });
            res.end(JSON.stringify(session));
        } else {
            res.writeHead(404, { 'Content-Type': 'text/plain' });
            res.end('Nenhuma sessão encontrada.');
        }
    } else if (req.url === '/editar' && req.method === 'GET') {
        // Editar sessão mockada
        if (session) {
            session.nome = 'Usuário Editado';  // Alterar um campo da sessão
            res.writeHead(200, { 'Content-Type': 'text/plain' });
            res.end('Sessão editada com sucesso!');
        } else {
            res.writeHead(404, { 'Content-Type': 'text/plain' });
            res.end('Nenhuma sessão para editar.');
        }
    } else if (req.url === '/remover' && req.method === 'GET') {
        // Remover sessão mockada
        if (session) {
            session = null;  // Zerar a sessão
            res.writeHead(200, { 'Content-Type': 'text/plain' });
            res.end('Sessão removida com sucesso!');
        } else {
            res.writeHead(404, { 'Content-Type': 'text/plain' });
            res.end('Nenhuma sessão para remover.');
        }
    } else {
        // Rota não encontrada
        res.writeHead(404, { 'Content-Type': 'text/plain' });
        res.end('Rota não encontrada.');
    }
});

// Iniciar o servidor na porta 3000
server.listen(3000, () => {
    console.log('Servidor rodando na porta 3000');
});

No comando acima, nós estamos simulando a criação de uma sessão dentro de um objeto simples (session) em memória.

Quando a rota /criar é acessada, a sessão é criada. Quando a rota /ler é acessada, os dados da sessão são exibidos (em formato JSON).

A rota /editar permite modificar os dados da sessão. Por fim, temos a rota /remover que remove a sessão, retornando null para o armazenamento.

Gerenciando suas sessões com o módulo express-session

Diferente do que você acabou de ver com o módulo HTTP, o processo de gerenciamento de sessões usando a biblioteca express-session, ocorre de uma maneira um pouco mais simples, vejamos.

index_express.js:

const express = require('express');
const session = require('express-session');

const app = express();

// Configurar o express-session
app.use(session({
    secret: 'segredo-super-seguro',  // Chave usada para assinar o cookie da sessão
    resave: false,                   // Evita salvar a sessão se nada mudou
    saveUninitialized: true,         // Salva sessões que ainda não foram inicializadas
    cookie: { maxAge: 3600000 }      // Tempo de expiração do cookie (1 hora)
}));

// Rota para criar uma sessão
app.get('/criar', (req, res) => {
    req.session.sessionId = '12345'; // Criar ou definir o ID da sessão
    req.session.nome = 'Usuário Sessão'; // Adicionar outros dados à sessão
    res.send('Sessão criada com sucesso!');
});

// Rota para ler os dados da sessão
app.get('/ler', (req, res) => {
    if (req.session.sessionId) {
        res.send(`Sessão ativa: ID = ${req.session.sessionId}, Nome = ${req.session.nome}`);
    } else {
        res.status(404).send('Nenhuma sessão ativa.');
    }
});

// Rota para editar a sessão
app.get('/editar', (req, res) => {
    if (req.session.sessionId) {
        req.session.nome = 'Usuário Editado'; // Editar um dado na sessão
        res.send('Sessão editada com sucesso!');
    } else {
        res.status(404).send('Nenhuma sessão para editar.');
    }
});

// Rota para remover a sessão
app.get('/remover', (req, res) => {
    if (req.session.sessionId) {
        req.session.destroy(err => {
            if (err) {
                return res.status(500).send('Erro ao remover a sessão.');
            }
            res.send('Sessão removida com sucesso!');
        });
    } else {
        res.status(404).send('Nenhuma sessão para remover.');
    }
});

// Iniciar o servidor
app.listen(3000, () => {
    console.log('Servidor rodando na porta 3000');
});

Note que além de importar a biblioteca do express-session, nós configuramos algumas informações a mais:

secret: é uma chave secreta usada para assinar o cookie da sessão e garantir a segurança da sessão. O cookie que armazena o identificador da sessão será assinado com essa chave.

resave: determina se a sessão deve ser salva novamente no armazenamento (memória, banco de dados, etc.) a cada requisição, mesmo que a sessão não tenha sido modificada.

saveUnitialized: controla se uma sessão deve ser salva no armazenamento quando ela é criada, mas ainda não foi modificada. Ou seja, se o objeto de sessão foi criado, mas nenhum dado foi adicionado, ele será salvo ou não, dependendo dessa configuração.

maxAge: define o tempo de vida do cookie em milissegundos. Após esse período, o cookie expira e a sessão será destruída. No exemplo, 3600000 é equivalente a 1 hora.

Além do maxAge setado dentro do argumento cookie, nós temos alguns outros, como:

secure: quando definido como true, o cookie só será enviado via conexões HTTPS. É uma boa prática ativar isso em produção para garantir que os cookies de sessão sejam transmitidos de forma segura.

httpOnly: se for true, o cookie será inacessível via JavaScript no lado do cliente, o que ajuda a proteger contra ataques de Cross-Site Scripting (XSS).

sameSite: define se o cookie deve ser enviado com requisições cross-site. Pode ser 'strict', 'lax', ou 'none':

  • 'strict': o cookie não será enviado em requisições cross-site.
  • 'lax': o cookie é enviado em algumas situações cross-site, como ao seguir links entre sites.
  • 'none': o cookie é enviado em todas as requisições, cross-site incluídas.

De resto, o processo de gerenciamento de uma sessão é feito quando acessamos o req.session para setar e recuperar os dados da mesma.

Se você estiver usando o navegador Google Chrome, você pode visualizar as seções clicando em Inspecionar Elemento > Application > Storage > Cookies:

Mas espere um momento... você disse cookies? 🧐  

Sim, por de baixo dos panos, tanto a biblioteca do express-session, quanto as operações que realizamos no módulo HTTP, todos aqueles dados estão sendo salvos dentro de cookies, e não dentro das sessões do navegador do usuário.

Sabe por que?

Pelo simples fato das nossas sessões estarem sendo gerenciadas pelo back-end da aplicação, e não pelo front-end.

E caso você ainda não saiba, só é possível setar cookies no back-end da aplicação rs

Se você desejar criar uma sessão que seja armazenada no sessionStorage do navegador do seu usuário, você vai precisar fazer isso usando puramente Javascript no seu Front-End.

Arquivos da lição

Os arquivos que você viu durante o decorrer desta lição, podem ser encontrados neste link.

Conclusão

Nesta lição, você aprendeu a gerenciar suas "sessões" (que na verdade são cookies disfarçados) em sua aplicação com NodeJS.

Até a próxima rs

Criadores de Conteúdo

Foto do William Lima
William Lima
Fundador da Micilini

Inventor nato, escreve conteudos de programação para o portal da micilini.

Torne-se um MIC 🤖

Mais de 100 mic's já estão conectados na plataforma.