Gerenciamento de sessões

O que é o estado da sessão?

O estado da sessão refere-se a dados que capturam o estado atual da interação do usuário com aplicativos, como um site ou um jogo.

Um aplicativo da Web típico mantém uma sessão aberta para cada usuário conectado durante todo o tempo em que ele estiver lá. O estado da sessão é a forma como os aplicativos lembram a identidade do usuário, as credenciais de login, as informações de personalização, as ações recentes, o carrinho de compras etc.

A leitura e a gravação dos dados da sessão em cada interação do usuário devem ser feitas sem prejudicar a experiência do usuário. Em segundo plano, o estado da sessão é um cache de dados para um usuário ou aplicativo específico que permite uma resposta rápida às ações do usuário. Portanto, enquanto a sessão do usuário estiver ativa, não há necessidade de sair e acessar constantemente o banco de dados central.

A última etapa do ciclo de vida do estado da sessão ocorre quando o usuário faz logoff. Alguns dados permanecerão no banco de dados para uso futuro, mas as informações transitórias podem ser descartadas após o término da sessão.

Desafios e práticas recomendadas para o estado da sessão

Compreender as práticas recomendadas de estado da sessão é fundamental para avaliar e resolver problemas comuns relacionados à sessão, como isolamento, volatilidade e persistência.

Enquanto a sessão está ativa, o aplicativo lê e grava exclusivamente no armazenamento de sessão na memória. Isso significa que as operações de gravação são mais rápidas, mas que não há tolerância na perda de dados. Como os dados no armazenamento de sessão não são um item simples instantâneo de outro banco de dados, eles devem ser muito duráveis e estar sempre disponíveis.

O estado da sessão é semelhante a um cache, mas tem ciclos de vida de leitura/gravação diferentes. Vejamos: um cache tolera a perda de dados e pode ser restaurado a qualquer momento a partir de um banco de dados primário. A gravação em um cache também requer a gravação no banco de dados subjacente. Por outro lado, o estado da sessão só pode ser restaurado a partir da fonte de dados primária quando a sessão do usuário é iniciada e persiste de volta à fonte quando a sessão termina.

O estado da sessão pode ser volátil ou permanente, o que significa que os dados podem ser descartados ou persistir no armazenamento em disco quando a sessão do usuário terminar. Um exemplo de dados de sessão voláteis pode ser o histórico de navegação de uma página em uma intranet corporativa: eles não precisam ser mantidos. Por outro lado, um carrinho de compras em um aplicativo de comércio eletrônico, é essencial para os negócios e deve ser mantido em armazenamento permanente.

O estado da sessão é armazenado como um par chave-valor, com o ID do usuário como chave e os dados da sessão como valor. Isso garante que as sessões do usuário não possam acessar outras informações.

O armazenamento do estado da sessão em um cache rápido na memória permite alguns cenários de análise on-line que, de outra forma, penalizariam um banco de dados transacional. Esses aplicativos incluem análises e painéis de controle em tempo real, mecanismos de recomendação e detecção de fraudes.

Como o Redis Enterprise faz isso rapidamente

Como usar o Redis Enterprise para gerenciamento de sessões

Vamos considerar um aplicativo de bate-papo de texto que usa o MySQL como banco de dados relacional, o Node.js como tecnologia de servidor de backend e o Redis Enterprise para gerenciamento de sessões. O frontend consiste em duas páginas: uma página inicial, onde os usuários se registram, e uma página de bate-papo, onde os usuários escrevem e enviam mensagens.

Para simplificar, mostraremos apenas o código do servidor. Explicaremos como implementar o ciclo de vida do estado da sessão no Node.js. Também omitiremos as páginas de visualização HTML e o restante do aplicativo.

Primeiro, o aplicativo carrega as dependências, incluindo a sessão, os objetos Redis e o cliente MySQL:

var express = require("express");
var session = require('express-session');
var mysql = require("mysql");
var redis = require("redis");
var redisStore = require('connect-redis')(session);
var redisClient = redis.createClient();
// mais dependências são carregadas aqui ...

Essas instruções criam objetos para gerenciar o roteamento da Web, a sessão, o banco de dados, o cache e as bibliotecas de sessão do Node.js. Em seguida, configure o Redis como um armazenamento de sessão:

app.use(session({
secret: 'mysecret',
// crear nuevo almacén redis.
store: new redisStore({ host: 'localhost', port: 6379, client: redisClient }),
saveUninitialized: false,
resave: false
}));

Em seguida, configure as rotas expressas do Node.js para a página inicial e a página de bate-papo, juntamente com o suporte para solicitações AJAX provenientes do cliente, incluindo login, logout e envio de comentários.

Quando um usuário solicita a página inicial, o servidor redireciona o usuário para a página chat.html ou exibe a página login.html, dependendo se o usuário está conectado ou não. O trecho a seguir mostra o código do controlador para o caminho da Web /get:

app.get('/',function(req,res){
// crear nuevo objeto de sesión.
if(req.session.key) {
// nenhuma sessão encontrada, vá para a página inicial
res.redirect('/chat');
} else {
// no se ha encontrado ninguna sesión, vaya a la página de inicio
res.render("login.html");
}
});

Quando o usuário envia os dados do formulário de login (com e-mail e senha), o cliente JavaScript AJAX envia os dados do formulário para o servidor. Neste exemplo, ele aciona a função executeLoginDbCommand (não mostrada aqui), que executa uma consulta SQL no banco de dados MySQL e retorna um objeto que contém os dados da sessão salvos anteriormente pelo usuário.

Se o login for bem-sucedido, os dados do usuário do MySQL serão salvos na sessão da Web com o suporte do armazenamento de sessão do Redis, e o código JavaScript do cliente redirecionará o usuário para a página de bate-papo:

app.post('/login',function(req, res){
// SQL Query irá comparar os dados de login e senha 
// do corpo da solicitação HTTP com os dados na tabela de usuários
executeLoginDbCommand(req.body.Email, req.body.Password, function(dbResult){
//
if(!dbResult) {
res.json({"success" : false,"message" : "Login failed ! Please register"});
} else {
req.session.key = dbResult;
res.json({"success" : true,"message" : "Login success."});
}
});
});

A página de bate-papo do aplicativo permite que os usuários leiam e enviem mensagens a outras pessoas conectadas ao aplicativo. Como os usuários só veem suas próprias interações de mensagens com outras pessoas, os dados retornados pelo servidor para solicitações da página de bate-papo mudam de usuário para usuário. E o mais importante, o acesso a esta página é restrito exclusivamente a usuários cadastrados. Verificar a chave de sessão revela se o usuário está logado ou não:

app.get('/chat',function(req,res){
if(req.session.key) {
//o usuário já está conectado,
//vamos para a página de bate-papo com o endereço de e-mail do usuário
res.render("chat.html",
{
email : req.session.key["UserEmail"],
name : req.session.key["UserName"]
});
} else {
// nenhuma sessão encontrada, vá para a página inicial
res.redirect("/");
}
});

Quando o usuário envia um novo comentário da página de bate-papo, o cliente JavaScript AJAX envia os dados do formulário para o servidor. Se o usuário estiver conectado, os comentários serão inseridos na tabela MySQL UserComments. Para fazer isso, use a função executeSendCommmentDbCommand (não mostrada aqui).

app.post("/sendComment",function(req,res){
// Esse comando SQL inserirá um novo comentário na
// tabela de usuários
app.post("/sendComment",function(req,res){
// Esse comando SQL inserirá um novo comentário na
// tabela de usuários
if(req.session.key) {
executeSendCommmentDbCommand(req.body.Email, req.body.Recipient, req.body.Comment, function(dbResult){
if(!dbResult) {
res.json({"success" : true, "message" : "Comment has been sent successfully."});
} else {
res.json({"success" : false, "message" : "SendComment failed!"});
}
});
} else {
res.json({"success" : false, "message" : "Please login first."});
}
});

Quando o usuário faz logout, o objeto de sessão é destruído e o usuário é redirecionado à página de login. Mas antes disso, a função executePersistSessionDbCommand (não mostrada aqui) salva a sessão do usuário na memória do banco de dados MySQL:

app.get('/logout',function(req,res){
// o usuário já está conectado, vamos limpar a sessão
// e redirecionar para a página de login.
if(req.session.key) {
executePersistSessionDbCommand(req.session, function(dbResult){
if(!dbResult) {
req.session.destroy(function(){
res.redirect("/");
} else {
res.json({"success" : false, "message" : "Session persistence failed!"});
}
});
});
} else {
res.redirect("/");
}
});

Esses fragmentos fornecem uma visão superficial de um aplicativo, usando o Redis como um armazenamento de sessão. Isso serve para mostrar como o Redis pode gerenciar o ciclo de vida do estado da sessão na memória em combinação com o armazenamento permanente do banco de dados, como o MySQL.


Próximas etapas