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