session: Biblioteca de sessão para nginx-module-lua – flexível e segura
Instalação
Se você ainda não configurou a assinatura do repositório RPM, inscreva-se. Então você pode prosseguir com os seguintes passos.
CentOS/RHEL 7 ou Amazon Linux 2
yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install lua-resty-session
CentOS/RHEL 8+, Fedora Linux, Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install lua5.1-resty-session
Para usar esta biblioteca Lua com NGINX, certifique-se de que nginx-module-lua está instalado.
Este documento descreve lua-resty-session v4.1.5 lançado em 24 de novembro de 2025.
lua-resty-session é uma biblioteca de sessão segura e flexível para OpenResty.
TL;DR;
- As sessões são imutáveis (cada salvamento gera uma nova sessão) e sem bloqueio.
- Os dados da sessão são criptografados com AES-256-GCM usando uma chave derivada com HKDF-SHA256 (no modo FIPS, usa PBKDF2 com SHA-256).
- A sessão tem um cabeçalho de tamanho fixo que é protegido com HMAC-SHA256 MAC com uma chave derivada usando HKDF-SHA256 (no modo FIPS, usa PBKDF2 com SHA-256).
- Os dados da sessão podem ser armazenados em um cookie sem estado ou em vários armazenamentos de backend.
- Um único cookie de sessão pode manter várias sessões entre diferentes públicos.
Nota: A versão 4.0.0 foi uma reescrita desta biblioteca com muitas lições aprendidas ao longo dos anos. Se você ainda usa uma versão mais antiga, consulte a documentação antiga.
Sinopse
worker_processes 1;
events {
worker_connections 1024;
}
http {
init_by_lua_block {
require "resty.session".init({
remember = true,
audience = "demo",
secret = "RaJKp8UQW1",
storage = "cookie",
})
}
server {
listen 8080;
server_name localhost;
default_type text/html;
location / {
content_by_lua_block {
ngx.say([[
<html>
<body>
<a href=/start>Iniciar o teste</a>
</body>
</html>
]])
}
}
location /start {
content_by_lua_block {
local session = require "resty.session".new()
session:set_subject("Fã do OpenResty")
session:set("quote", "A rápida raposa marrom salta sobre o cachorro preguiçoso")
local ok, err = session:save()
ngx.say(string.format([[
<html>
<body>
<p>Sessão iniciada (%s)</p>
<p><a href=/started>Verifique se realmente foi</a></p>
</body>
</html>
]], err or "sem erro"))
}
}
location /started {
content_by_lua_block {
local session, err = require "resty.session".start()
ngx.say(string.format([[
<html>
<body>
<p>A sessão foi iniciada por %s (%s)</p>
<p><blockquote>%s</blockquote></p>
<p><a href=/modify>Modificar a sessão</a></p>
</body>
</html>
]],
session:get_subject() or "Anônimo",
err or "sem erro",
session:get("quote") or "sem citação"
))
}
}
location /modify {
content_by_lua_block {
local session, err = require "resty.session".start()
session:set_subject("Fã do Lua")
session:set("quote", "Lorem ipsum dolor sit amet")
local _, err_save = session:save()
ngx.say(string.format([[
<html>
<body>
<p>A sessão foi modificada (%s)</p>
<p><a href=/modified>Verifique se foi modificada</a></p>
</body>
</html>
]], err or err_save or "sem erro"))
}
}
location /modified {
content_by_lua_block {
local session, err = require "resty.session".start()
ngx.say(string.format([[
<html>
<body>
<p>A sessão foi iniciada por %s (%s)</p>
<p><blockquote>%s</blockquote></p>
<p><a href=/destroy>Destruir a sessão</a></p>
</body>
</html>
]],
session:get_subject() or "Anônimo",
err or "sem erro",
session:get("quote") or "sem citação"
))
}
}
location /destroy {
content_by_lua_block {
local ok, err = require "resty.session".destroy()
ngx.say(string.format([[
<html>
<body>
<p>A sessão foi destruída (%s)</p>
<p><a href=/destroyed>Verifique se realmente foi?</a></p>
</body>
</html>
]], err or "sem erro"))
}
}
location /destroyed {
content_by_lua_block {
local session, err = require "resty.session".open()
ngx.say(string.format([[
<html>
<body>
<p>A sessão foi realmente destruída, você é conhecido como %s (%s)</p>
<p><a href=/>Começar novamente</a></p>
</body>
</html>
]],
session:get_subject() or "Anônimo",
err or "sem erro"
))
}
}
}
}
Configuração
A configuração pode ser dividida em configuração de sessão genérica e configuração de armazenamento do lado do servidor.
Aqui está um exemplo:
init_by_lua_block {
require "resty.session".init({
remember = true,
store_metadata = true,
secret = "RaJKp8UQW1",
secret_fallbacks = {
"X88FuG1AkY",
"fxWNymIpbb",
},
storage = "postgres",
postgres = {
username = "my-service",
password = "kVgIXCE5Hg",
database = "sessions",
},
})
}
Configuração da Sessão
A configuração da sessão pode ser passada para as funções de inicialização, construtor e ajudante.
Aqui estão as possíveis opções de configuração da sessão:
| Opção | Padrão | Descrição |
|---|---|---|
secret |
nil |
Segredo usado para a derivação da chave. O segredo é hashado com SHA-256 antes de ser usado. Ex: "RaJKp8UQW1". |
secret_fallbacks |
nil |
Array de segredos que podem ser usados como segredos alternativos (ao fazer rotação de chave), Ex: { "6RfrAYYzYq", "MkbTkkyF9C" }. |
ikm |
(aleatório) | Material de chave inicial (ou ikm) pode ser especificado diretamente (sem usar um segredo) com exatamente 32 bytes de dados. Ex: "5ixIW4QVMk0dPtoIhn41Eh1I9enP2060" |
ikm_fallbacks |
nil |
Array de materiais de chave inicial que podem ser usados como chaves alternativas (ao fazer rotação de chave), Ex: { "QvPtlPKxOKdP5MCu1oI3lOEXIVuDckp7" }. |
cookie_prefix |
nil |
Prefixo do cookie, use nil, "__Host-" ou "__Secure-". |
cookie_name |
"session" |
Nome do cookie de sessão, ex: "session". |
cookie_path |
"/" |
Caminho do cookie, ex: "/". |
cookie_domain |
nil |
Domínio do cookie, ex: "example.com" |
cookie_http_only |
true |
Marcar cookie como apenas HTTP, use true ou false. |
cookie_secure |
nil |
Marcar cookie como seguro, use nil, true ou false. |
cookie_priority |
nil |
Prioridade do cookie, use nil, "Low", "Medium" ou "High". |
cookie_same_site |
"Lax" |
Política de mesmo site do cookie, use nil, "Lax", "Strict", "None" ou "Default" |
cookie_same_party |
nil |
Marcar cookie com a flag de mesmo partido, use nil, true ou false. |
cookie_partitioned |
nil |
Marcar cookie com a flag de particionado, use nil, true ou false. |
remember |
false |
Habilitar ou desabilitar sessões persistentes, use nil, true ou false. |
remember_safety |
"Medium" |
Complexidade da derivação da chave do cookie de lembrança, use nil, "None" (rápido), "Low", "Medium", "High" ou "Very High" (lento). |
remember_cookie_name |
"remember" |
Nome do cookie de sessão persistente, ex: "remember". |
audience |
"default" |
Público da sessão, ex: "my-application". |
subject |
nil |
Sujeito da sessão, ex: "[email protected]". |
enforce_same_subject |
false |
Quando definido como true, os públicos precisam compartilhar o mesmo sujeito. A biblioteca remove dados de público que não correspondem ao sujeito ao salvar. |
stale_ttl |
10 |
Quando a sessão é salva, uma nova sessão é criada, stale ttl especifica quanto tempo a antiga ainda pode ser usada, ex: 10 (em segundos). |
idling_timeout |
900 |
O tempo limite de inatividade especifica quanto tempo a sessão pode estar inativa até ser considerada inválida, ex: 900 (15 minutos) (em segundos), 0 desabilita as verificações e toques. |
rolling_timeout |
3600 |
O tempo limite rolante especifica quanto tempo a sessão pode ser usada até precisar ser renovada, ex: 3600 (uma hora) (em segundos), 0 desabilita as verificações e rolamentos. |
absolute_timeout |
86400 |
O tempo limite absoluto limita quanto tempo a sessão pode ser renovada, até que a re-autenticação seja necessária, ex: 86400 (um dia) (em segundos), 0 desabilita as verificações. |
remember_rolling_timeout |
604800 |
O tempo limite de lembrança especifica quanto tempo a sessão persistente é considerada válida, ex: 604800 (uma semana) (em segundos), 0 desabilita as verificações e rolamentos. |
remember_absolute_timeout |
2592000 |
O tempo limite absoluto de lembrança limita quanto tempo a sessão persistente pode ser renovada, até que a re-autenticação seja necessária, ex: 2592000 (30 dias) (em segundos), 0 desabilita as verificações. |
hash_storage_key |
false |
Se deve ou não hash a chave de armazenamento. Com a chave de armazenamento hashada, é impossível descriptografar dados no lado do servidor sem ter um cookie também, use nil, true ou false. |
hash_subject |
false |
Se deve ou não hash o sujeito quando store_metadata está habilitado, ex: por razões de PII. |
store_metadata |
false |
Se deve ou não armazenar também os metadados das sessões, como coletar dados de sessões para um público específico pertencente a um sujeito específico. |
touch_threshold |
60 |
O limiar de toque controla com que frequência ou infrequentemente o session:refresh toca o cookie, ex: 60 (um minuto) (em segundos) |
compression_threshold |
1024 |
O limiar de compressão controla quando os dados são desinflados, ex: 1024 (um kilobyte) (em bytes), 0 desabilita a compressão. |
bind |
nil |
Vincular a sessão a dados adquiridos da solicitação HTTP ou conexão, use ip, scheme, user-agent. Ex: { "scheme", "user-agent" } calculará MAC utilizando também a solicitação HTTP Scheme e o cabeçalho User-Agent. |
request_headers |
nil |
Conjunto de cabeçalhos a serem enviados para o upstream, use id, audience, subject, timeout, idling-timeout, rolling-timeout, absolute-timeout. Ex: { "id", "timeout" } definirá os cabeçalhos de solicitação Session-Id e Session-Timeout quando set_headers for chamado. |
response_headers |
nil |
Conjunto de cabeçalhos a serem enviados para o downstream, use id, audience, subject, timeout, idling-timeout, rolling-timeout, absolute-timeout. Ex: { "id", "timeout" } definirá os cabeçalhos de resposta Session-Id e Session-Timeout quando set_headers for chamado. |
storage |
nil |
O armazenamento é responsável por armazenar dados da sessão, use nil ou "cookie" (os dados são armazenados em cookie), "dshm", "file", "memcached", "mysql", "postgres", "redis" ou "shm", ou dê um nome de módulo personalizado ("custom-storage"), ou uma tabela que implementa a interface de armazenamento de sessão. |
dshm |
nil |
Configuração para armazenamento dshm, ex: { prefix = "sessions" } (veja abaixo) |
file |
nil |
Configuração para armazenamento de arquivo, ex: { path = "/tmp", suffix = "session" } (veja abaixo) |
memcached |
nil |
Configuração para armazenamento memcached, ex: { prefix = "sessions" } (veja abaixo) |
mysql |
nil |
Configuração para armazenamento MySQL / MariaDB, ex: { database = "sessions" } (veja abaixo) |
postgres |
nil |
Configuração para armazenamento Postgres, ex: { database = "sessions" } (veja abaixo) |
redis |
nil |
Configuração para armazenamento Redis / Redis Sentinel / Redis Cluster, ex: { prefix = "sessions" } (veja abaixo) |
shm |
nil |
Configuração para armazenamento em memória compartilhada, ex: { zone = "sessions" } |
["custom-storage"] |
nil |
configuração de armazenamento personalizado (carregado com require "custom-storage"). |
Configuração de Armazenamento em Cookie
Ao armazenar dados em cookie, não há configuração adicional necessária, apenas defina o storage como nil ou "cookie".
Configuração de Armazenamento DSHM
Com o armazenamento DHSM você pode usar as seguintes configurações (defina o storage como "dshm"):
| Opção | Padrão | Descrição |
|---|---|---|
prefix |
nil |
O prefixo para as chaves armazenadas no DSHM. |
suffix |
nil |
O sufixo para as chaves armazenadas no DSHM. |
host |
"127.0.0.1" |
O host para conectar. |
port |
4321 |
A porta para conectar. |
connect_timeout |
nil |
Controla o valor padrão de tempo limite usado no método connect do objeto de socket TCP/unix-domain. |
send_timeout |
nil |
Controla o valor padrão de tempo limite usado no método send do objeto de socket TCP/unix-domain. |
read_timeout |
nil |
Controla o valor padrão de tempo limite usado no método receive do objeto de socket TCP/unix-domain. |
keepalive_timeout |
nil |
Controla o tempo máximo de inatividade das conexões no pool de conexões. |
pool |
nil |
Um nome personalizado para o pool de conexões em uso. |
pool_size |
nil |
O tamanho do pool de conexões. |
backlog |
nil |
Um tamanho de fila a ser usado quando o pool de conexões estiver cheio (configurado com pool_size). |
ssl |
nil |
Habilitar SSL. |
ssl_verify |
nil |
Verificar o certificado do servidor. |
server_name |
nil |
O nome do servidor para a nova extensão TLS Server Name Indication (SNI). |
Consulte ngx-distributed-shm para obter as dependências necessárias instaladas.
Configuração de Armazenamento em Arquivo
Com o armazenamento em arquivo você pode usar as seguintes configurações (defina o storage como "file"):
| Opção | Padrão | Descrição |
|---|---|---|
prefix |
nil |
Prefixo do arquivo para o arquivo de sessão. |
suffix |
nil |
Sufixo do arquivo (ou extensão sem .) para o arquivo de sessão. |
pool |
nil |
Nome do pool de threads sob o qual a gravação do arquivo acontece (disponível apenas no Linux). |
path |
(diretório tmp) | Caminho (ou diretório) sob o qual os arquivos de sessão são criados. |
A implementação requer LuaFileSystem, que você pode instalar com LuaRocks:
❯ luarocks install LuaFileSystem
Configuração de Armazenamento Memcached
Com o armazenamento Memcached você pode usar as seguintes configurações (defina o storage como "memcached"):
| Opção | Padrão | Descrição |
|---|---|---|
prefix |
nil |
Prefixo para as chaves armazenadas no memcached. |
suffix |
nil |
Sufixo para as chaves armazenadas no memcached. |
host |
127.0.0.1 |
O host para conectar. |
port |
11211 |
A porta para conectar. |
socket |
nil |
O arquivo de socket para conectar. |
connect_timeout |
nil |
Controla o valor padrão de tempo limite usado no método connect do objeto de socket TCP/unix-domain. |
send_timeout |
nil |
Controla o valor padrão de tempo limite usado no método send do objeto de socket TCP/unix-domain. |
read_timeout |
nil |
Controla o valor padrão de tempo limite usado no método receive do objeto de socket TCP/unix-domain. |
keepalive_timeout |
nil |
Controla o tempo máximo de inatividade das conexões no pool de conexões. |
pool |
nil |
Um nome personalizado para o pool de conexões em uso. |
pool_size |
nil |
O tamanho do pool de conexões. |
backlog |
nil |
Um tamanho de fila a ser usado quando o pool de conexões estiver cheio (configurado com pool_size). |
ssl |
false |
Habilitar SSL |
ssl_verify |
nil |
Verificar o certificado do servidor |
server_name |
nil |
O nome do servidor para a nova extensão TLS Server Name Indication (SNI). |
Configuração de Armazenamento MySQL / MariaDB
Com o armazenamento MySQL / MariaDB você pode usar as seguintes configurações (defina o storage como "mysql"):
| Opção | Padrão | Descrição |
|---|---|---|
host |
"127.0.0.1" |
O host para conectar. |
port |
3306 |
A porta para conectar. |
socket |
nil |
O arquivo de socket para conectar. |
username |
nil |
O nome de usuário do banco de dados para autenticação. |
password |
nil |
Senha para autenticação, pode ser necessária dependendo da configuração do servidor. |
charset |
"ascii" |
O conjunto de caracteres usado na conexão MySQL. |
database |
nil |
O nome do banco de dados para conectar. |
table_name |
"sessions" |
Nome da tabela do banco de dados para armazenar dados da sessão. |
table_name_meta |
"sessions_meta" |
Nome da tabela de metadados do banco de dados para armazenar metadados da sessão. |
max_packet_size |
1048576 |
O limite superior para os pacotes de resposta enviados do servidor MySQL (em bytes). |
connect_timeout |
nil |
Controla o valor padrão de tempo limite usado no método connect do objeto de socket TCP/unix-domain. |
send_timeout |
nil |
Controla o valor padrão de tempo limite usado no método send do objeto de socket TCP/unix-domain. |
read_timeout |
nil |
Controla o valor padrão de tempo limite usado no método receive do objeto de socket TCP/unix-domain. |
keepalive_timeout |
nil |
Controla o tempo máximo de inatividade das conexões no pool de conexões. |
pool |
nil |
Um nome personalizado para o pool de conexões em uso. |
pool_size |
nil |
O tamanho do pool de conexões. |
backlog |
nil |
Um tamanho de fila a ser usado quando o pool de conexões estiver cheio (configurado com pool_size). |
ssl |
false |
Habilitar SSL. |
ssl_verify |
nil |
Verificar o certificado do servidor. |
Você também precisa criar as seguintes tabelas no seu banco de dados:
--
-- Tabela do banco de dados que armazena dados da sessão.
--
CREATE TABLE IF NOT EXISTS sessions (
sid CHAR(43) PRIMARY KEY,
name VARCHAR(255),
data MEDIUMTEXT,
exp DATETIME,
INDEX (exp)
) CHARACTER SET ascii;
--
-- Tabela de metadados das sessões.
--
-- Isso é necessário apenas se você quiser armazenar metadados da sessão.
--
CREATE TABLE IF NOT EXISTS sessions_meta (
aud VARCHAR(255),
sub VARCHAR(255),
sid CHAR(43),
PRIMARY KEY (aud, sub, sid),
CONSTRAINT FOREIGN KEY (sid) REFERENCES sessions(sid) ON DELETE CASCADE ON UPDATE CASCADE
) CHARACTER SET ascii;
Configuração Postgres
Com o armazenamento Postgres você pode usar as seguintes configurações (defina o storage como "postgres"):
| Opção | Padrão | Descrição |
|---|---|---|
host |
"127.0.0.1" |
O host para conectar. |
port |
5432 |
A porta para conectar. |
application |
5432 |
Defina o nome da conexão conforme exibido em pg_stat_activity (padrão é "pgmoon"). |
username |
"postgres" |
O nome de usuário do banco de dados para autenticação. |
password |
nil |
Senha para autenticação, pode ser necessária dependendo da configuração do servidor. |
database |
nil |
O nome do banco de dados para conectar. |
table_name |
"sessions" |
Nome da tabela do banco de dados para armazenar dados da sessão (pode ser prefixado com schema do banco). |
table_name_meta |
"sessions_meta" |
Nome da tabela de metadados do banco de dados para armazenar metadados da sessão (pode ser prefixado com schema do banco). |
connect_timeout |
nil |
Controla o valor padrão de tempo limite usado no método connect do objeto de socket TCP/unix-domain. |
send_timeout |
nil |
Controla o valor padrão de tempo limite usado no método send do objeto de socket TCP/unix-domain. |
read_timeout |
nil |
Controla o valor padrão de tempo limite usado no método receive do objeto de socket TCP/unix-domain. |
keepalive_timeout |
nil |
Controla o tempo máximo de inatividade das conexões no pool de conexões. |
pool |
nil |
Um nome personalizado para o pool de conexões em uso. |
pool_size |
nil |
O tamanho do pool de conexões. |
backlog |
nil |
Um tamanho de fila a ser usado quando o pool de conexões estiver cheio (configurado com pool_size). |
ssl |
false |
Habilitar SSL. |
ssl_verify |
nil |
Verificar o certificado do servidor. |
Você também precisa criar as seguintes tabelas no seu banco de dados:
--
-- Tabela do banco de dados que armazena dados da sessão.
--
CREATE TABLE IF NOT EXISTS sessions (
sid TEXT PRIMARY KEY,
name TEXT,
data TEXT,
exp TIMESTAMP WITH TIME ZONE
);
CREATE INDEX ON sessions (exp);
--
-- Tabela de metadados das sessões.
--
-- Isso é necessário apenas se você quiser armazenar metadados da sessão.
--
CREATE TABLE IF NOT EXISTS sessions_meta (
aud TEXT,
sub TEXT,
sid TEXT REFERENCES sessions (sid) ON DELETE CASCADE ON UPDATE CASCADE,
PRIMARY KEY (aud, sub, sid)
);
A implementação requer pgmoon, que você pode instalar com LuaRocks:
❯ luarocks install pgmoon
Configuração Redis
A biblioteca de sessão suporta conexões Redis simples, Redis Sentinel e Redis Cluster. Configurações comuns entre todas elas:
| Opção | Padrão | Descrição |
|---|---|---|
prefix |
nil |
Prefixo para as chaves armazenadas no Redis. |
suffix |
nil |
Sufixo para as chaves armazenadas no Redis. |
username |
nil |
O nome de usuário do banco de dados para autenticação. |
password |
nil |
Senha para autenticação. |
connect_timeout |
nil |
Controla o valor padrão de tempo limite usado no método connect do objeto de socket TCP/unix-domain. |
send_timeout |
nil |
Controla o valor padrão de tempo limite usado no método send do objeto de socket TCP/unix-domain. |
read_timeout |
nil |
Controla o valor padrão de tempo limite usado no método receive do objeto de socket TCP/unix-domain. |
keepalive_timeout |
nil |
Controla o tempo máximo de inatividade das conexões no pool de conexões. |
pool |
nil |
Um nome personalizado para o pool de conexões em uso. |
pool_size |
nil |
O tamanho do pool de conexões. |
backlog |
nil |
Um tamanho de fila a ser usado quando o pool de conexões estiver cheio (configurado com pool_size). |
ssl |
false |
Habilitar SSL |
ssl_verify |
nil |
Verificar o certificado do servidor |
server_name |
nil |
O nome do servidor para a nova extensão TLS Server Name Indication (SNI). |
A implementação redis simples é selecionada quando você não passa nem sentinels nem nodes, o que levaria a selecionar a implementação sentinel ou cluster.
Configuração Redis Simples
Redis simples tem as seguintes opções de configuração adicionais (defina o storage como "redis"):
| Opção | Padrão | Descrição |
|---|---|---|
host |
"127.0.0.1" |
O host para conectar. |
port |
6379 |
A porta para conectar. |
socket |
nil |
O arquivo de socket para conectar. |
Configuração Redis Sentinel
Redis Sentinel tem as seguintes opções de configuração adicionais (defina o storage como "redis" e configure os sentinels):
| Opção | Padrão | Descrição |
|---|---|---|
master |
nil |
Nome do mestre. |
role |
nil |
"master" ou "slave". |
socket |
nil |
O arquivo de socket para conectar. |
sentinels |
nil |
Redis Sentinels. |
sentinel_username |
nil |
Nome de usuário opcional do sentinel. |
sentinel_password |
nil |
Senha opcional do sentinel. |
database |
nil |
O banco de dados para conectar. |
Os sentinels são um array de registros Sentinel:
| Opção | Padrão | Descrição |
|---|---|---|
host |
nil |
O host para conectar. |
port |
nil |
A porta para conectar. |
A implementação sentinel é selecionada quando você passa sentinels como parte da configuração redis (e não passa nodes, o que selecionaria a implementação cluster).
A implementação requer lua-resty-redis-connector, que você pode instalar com LuaRocks:
❯ luarocks install lua-resty-redis-connector
Configuração Redis Cluster
Redis Cluster tem as seguintes opções de configuração adicionais (defina o storage como "redis" e configure os nodes):
| Opção | Padrão | Descrição |
|---|---|---|
name |
nil |
Nome do cluster Redis. |
nodes |
nil |
Nós do cluster Redis. |
lock_zone |
nil |
Nome do dicionário compartilhado para bloqueios. |
lock_prefix |
nil |
Prefixo do nome do dicionário compartilhado para bloqueio. |
max_redirections |
nil |
Máximo de tentativas de redirecionamento. |
max_connection_attempts |
nil |
Máximo de tentativas de conexão. |
max_connection_timeout |
nil |
Tempo máximo de conexão total entre as tentativas. |
Os nodes são um array de registros de nós do Cluster:
| Opção | Padrão | Descrição |
|---|---|---|
ip |
"127.0.0.1" |
O endereço IP para conectar. |
port |
6379 |
A porta para conectar. |
A implementação cluster é selecionada quando você passa nodes como parte da configuração redis.
Para que o cluster funcione corretamente, você precisa configurar lock_zone, então adicione isso à sua configuração do Nginx:
lua_shared_dict redis_cluster_locks 100k;
E defina o lock_zone como "redis_cluster_locks".
A implementação requer resty-redis-cluster ou kong-redis-cluster, que você pode instalar com LuaRocks:
❯ luarocks install resty-redis-cluster
## ou
❯ luarocks install kong-redis-cluster
Configuração SHM
Com o armazenamento SHM você pode usar as seguintes configurações (defina o storage como "shm"):
| Opção | Padrão | Descrição |
|---|---|---|
prefix |
nil |
Prefixo para as chaves armazenadas no SHM. |
suffix |
nil |
Sufixo para as chaves armazenadas no SHM. |
zone |
"sessions" |
Um nome da zona de memória compartilhada. |
Você também precisará criar um dicionário compartilhado zone no Nginx:
lua_shared_dict sessions 10m;
Nota: você pode precisar ajustar o tamanho da zona de memória compartilhada de acordo com suas necessidades.
API
Os docs da API gerados pelo LDoc também podem ser visualizados em bungle.github.io/lua-resty-session.
Inicialização
session.init
sintaxe: session.init(configuração)
Inicializa a biblioteca de sessão.
Esta função pode ser chamada nas fases init ou init_worker no OpenResty para definir a configuração padrão global para todas as instâncias de sessão criadas por esta biblioteca.
require "resty.session".init({
audience = "my-application",
storage = "redis",
redis = {
username = "session",
password = "storage",
},
})
Consulte configuração para possíveis configurações.
Construtores
session.new
sintaxe: session = session.new(configuração)
Cria uma nova instância de sessão.
local session = require "resty.session".new()
-- OU
local session = require "resty.session".new({
audience = "my-application",
})
Consulte configuração para possíveis configurações.
Ajudantes
session.open
sintaxe: session, err, exists = session.open(configuração)
Isso pode ser usado para abrir uma sessão, e retornará uma sessão existente ou uma nova sessão. O parâmetro de retorno exists (um booleano) informa se era uma sessão existente ou nova que foi retornada. O err (uma string) contém uma mensagem do porquê a abertura pode ter falhado (a função ainda retornará session também).
local session = require "resty.session".open()
-- OU
local session, err, exists = require "resty.session".open({
audience = "my-application",
})
Consulte configuração para possíveis configurações.
session.start
sintaxe: session, err, exists, refreshed = session.start(configuração)
Isso pode ser usado para iniciar uma sessão, e retornará uma sessão existente ou uma nova sessão. No caso de haver uma sessão existente, a sessão será atualizada também (conforme necessário). O parâmetro de retorno exists (um booleano) informa se era uma sessão existente ou nova que foi retornada. O refreshed (um booleano) informa se a chamada para refresh foi bem-sucedida. O err (uma string) contém uma mensagem do porquê a abertura ou atualização pode ter falhado (a função ainda retornará session também).
local session = require "resty.session".start()
-- OU
local session, err, exists, refreshed = require "resty.session".start({
audience = "my-application",
})
Consulte configuração para possíveis configurações.
session.logout
sintaxe: ok, err, exists, logged_out = session.logout(configuração)
Desconecta de um público específico.
Um único cookie de sessão pode ser compartilhado entre vários públicos (ou aplicações), portanto, há a necessidade de poder desconectar de apenas um único público enquanto mantém a sessão para os outros públicos. O parâmetro de retorno exists (um booleano) informa se a sessão existia. O parâmetro de retorno logged_out (um booleano) sinaliza se a sessão existia e também foi desconectada. O err (uma string) contém uma razão pela qual a sessão não existia ou por que a desconexão falhou. O ok (verdadeiro) será true quando a sessão existia e foi desconectada com sucesso.
Quando há apenas um único público, isso pode ser considerado igual a session.destroy.
Quando o último público é desconectado, o cookie também será destruído e invalidado no cliente.
require "resty.session".logout()
-- OU
local ok, err, exists, logged_out = require "resty.session".logout({
audience = "my-application",
})
Consulte configuração para possíveis configurações.
session.destroy
sintaxe: ok, err, exists, destroyed = session.destroy(configuração)
Destrói toda a sessão e limpa os cookies.
Um único cookie de sessão pode ser compartilhado entre vários públicos (ou aplicações), portanto, há a necessidade de poder desconectar de apenas um único público enquanto mantém a sessão para os outros públicos. O parâmetro de retorno exists (um booleano) informa se a sessão existia. O parâmetro de retorno destroyed (um booleano) sinaliza se a sessão existia e também foi destruída. O err (uma string) contém uma razão pela qual a sessão não existia ou por que a desconexão falhou. O ok (verdadeiro) será true quando a sessão existia e foi desconectada com sucesso.
require "resty.session".destroy()
-- OU
local ok, err, exists, destroyed = require "resty.session".destroy({
cookie_name = "auth",
})
Consulte configuração para possíveis configurações.
Métodos de Instância
session:open
sintaxe: ok, err = session:open()
Isso pode ser usado para abrir uma sessão. Retorna true quando a sessão foi aberta e validada. Caso contrário, retorna nil e uma mensagem de erro.
local session = require "resty.session".new()
local ok, err = session:open()
if ok then
-- a sessão existe
else
-- a sessão não existia ou era inválida
end
session:save
sintaxe: ok, err = session:save()
Salva os dados da sessão e emite um novo cookie de sessão com um novo id de sessão. Quando remember está habilitado, também emitirá um novo cookie persistente e possivelmente salvará os dados no armazenamento de backend. Retorna true quando a sessão foi salva. Caso contrário, retorna nil e uma mensagem de erro.
local session = require "resty.session".new()
session:set_subject("john")
local ok, err = session:save()
if not ok then
-- erro ao salvar a sessão
end
session:touch
sintaxe: ok, err = session:touch()
Atualiza o deslocamento de inatividade da sessão enviando um cookie de sessão atualizado. Ele apenas envia o cookie do cliente e nunca chama nenhuma API de armazenamento de sessão de backend. Normalmente, o session:refresh é usado para chamar isso indiretamente. Em caso de erro, retorna nil e uma mensagem de erro, caso contrário, true.
local session, err, exists = require "resty.session".open()
if exists then
ok, err = session:touch()
end
session:refresh
sintaxe: ok, err = session:refresh()
Ou salva a sessão (criando um novo id de sessão) ou toca a sessão dependendo de se o tempo limite rolante está se aproximando, o que significa que, por padrão, quando 3/4 do tempo limite rolante é gasto, ou seja, 45 minutos com o tempo limite rolante padrão de uma hora. O toque tem um limiar, por padrão um minuto, então pode ser pulado em alguns casos (você pode chamar session:touch() para forçá-lo). Em caso de erro, retorna nil e uma mensagem de erro, caso contrário, true.
local session, err, exists = require "resty.session".open()
if exists then
local ok, err = session:refresh()
end
O código acima se parece um pouco com o ajudante session.start().
session:logout
sintaxe: ok, err = session:logout()
Logout destrói a sessão ou apenas limpa os dados para o público atual, e salva (desconectando do público atual). Em caso de erro, retorna nil e uma mensagem de erro, caso contrário, true.
local session, err, exists = require "resty.session".open()
if exists then
local ok, err = session:logout()
end
session:destroy
sintaxe: ok, err = session:destroy()
Destrói a sessão e limpa os cookies. Em caso de erro, retorna nil e uma mensagem de erro, caso contrário, true.
local session, err, exists = require "resty.session".open()
if exists then
local ok, err = session:destroy()
end
session:close
sintaxe: session:close()
Apenas fecha a instância da sessão para que não possa mais ser usada.
local session = require "resty.session".new()
session:set_subject("john")
local ok, err = session:save()
if not ok then
-- erro ao salvar a sessão
end
session:close()
session:set_data
sintaxe: session:set_data(data)
Define os dados da sessão. O data precisa ser uma tabela.
local session, err, exists = require "resty.session".open()
if not exists then
session:set_data({
cart = {},
})
session:save()
end
session:get_data
sintaxe: data = session:get_data()
Obtém os dados da sessão.
local session, err, exists = require "resty.session".open()
if exists then
local data = session:get_data()
ngx.req.set_header("Authorization", "Bearer " .. data.access_token)
end
session:set
sintaxe: session:set(key, value)
Define um valor na sessão.
local session, err, exists = require "resty.session".open()
if not exists then
session:set("access-token", "eyJ...")
session:save()
end
session:get
sintaxe: value = session:get(key)
Obtém um valor da sessão.
local session, err, exists = require "resty.session".open()
if exists then
local access_token = session:get("access-token")
ngx.req.set_header("Authorization", "Bearer " .. access_token)
end
session:set_audience
sintaxe: session:set_audience(audience)
Define o público da sessão.
local session = require "resty.session".new()
session.set_audience("my-service")
session:get_audience
sintaxe: audience = session:get_audience()
Define o sujeito da sessão.
session:set_subject
sintaxe: session:set_subject(subject)
Define o sujeito da sessão.
local session = require "resty.session".new()
session.set_subject("[email protected]")
session:get_subject
sintaxe: subject = session:get_subject()
Obtém o sujeito da sessão.
local session, err, exists = require "resty.session".open()
if exists then
local subject = session.get_subject()
end
session:get_property
sintaxe: value = session:get_property(name)
Obtém uma propriedade da sessão. Possíveis nomes de propriedades:
"id": 43 bytes de id da sessão (igual ao nonce, mas codificado em base64 url)"nonce": 32 bytes de nonce (igual ao id da sessão, mas em bytes brutos)"audience": Público atual da sessão"subject": Sujeito atual da sessão"timeout": Tempo limite mais próximo (em segundos) (o que resta dele)"idling-timeout"`: Tempo limite de inatividade da sessão (em segundos) (o que resta dele)"rolling-timeout"`: Tempo limite rolante da sessão (em segundos) (o que resta dele)"absolute-timeout"`: Tempo limite absoluto da sessão (em segundos) (o que resta dele)
Nota: o valor retornado pode ser nil.
local session, err, exists = require "resty.session".open()
if exists then
local timeout = session.get_property("timeout")
end
session:set_remember
sintaxe: session:set_remember(value)
Define sessões persistentes ativadas/desativadas.
Em muitos formulários de login, o usuário tem a opção de "lembrar-me". Você pode chamar esta função com base no que o usuário selecionou.
local session = require "resty.session".new()
if ngx.var.args.remember then
session:set_remember(true)
end
session:set_subject(ngx.var.args.username)
session:save()
session:get_remember
sintaxe: remember = session:get_remember()
Obtém o estado das sessões persistentes.
local session, err, exists = require "resty.session".open()
if exists then
local remember = session.get_remember()
end
session:clear_request_cookie
sintaxe: ok, err = session:clear_request_cookie()
Modifica os cabeçalhos da solicitação removendo os cookies relacionados à sessão. Isso é útil quando você usa a biblioteca de sessão em um servidor proxy e não deseja que os cookies da sessão sejam encaminhados para o serviço upstream. Em caso de erro, retorna nil e uma mensagem de erro, caso contrário, true (que pode ser ignorado).
local session, err, exists = require "resty.session".open()
if exists then
session:clear_request_cookie()
end
session:set_headers
sintaxe: ok, err = session:set_headers(arg1, arg2, ...)
Define cabeçalhos de solicitação e resposta com base na configuração. Em caso de erro, retorna nil e uma mensagem de erro, caso contrário, true (que pode ser ignorado).
local session, err, exists = require "resty.session".open({
request_headers = { "audience", "subject", "id" },
response_headers = { "timeout", "idling-timeout", "rolling-timeout", "absolute-timeout" },
})
if exists then
session:set_headers()
end
Quando chamado sem argumentos, ele definirá os cabeçalhos de solicitação configurados com request_headers e os cabeçalhos de resposta configurados com response_headers.
Consulte configuração para possíveis nomes de cabeçalhos.
session:set_request_headers
sintaxe: ok, err = session:set_request_headers(arg1, arg2, ...)
Define cabeçalhos de solicitação. Em caso de erro, retorna nil e uma mensagem de erro, caso contrário, true (que pode ser ignorado).
local session, err, exists = require "resty.session".open()
if exists then
session:set_request_headers("audience", "subject", "id")
end
Quando chamado sem argumentos, ele definirá os cabeçalhos de solicitação configurados com request_headers.
Consulte configuração para possíveis nomes de cabeçalhos.
session:set_response_headers
sintaxe: ok, err = session:set_response_headers(arg1, arg2, ...)
Define cabeçalhos de resposta. Em caso de erro, retorna nil e uma mensagem de erro, caso contrário, true (que pode ser ignorado).
local session, err, exists = require "resty.session".open()
if exists then
session:set_response_headers("timeout", "idling-timeout", "rolling-timeout", "absolute-timeout")
end
Quando chamado sem argumentos, ele definirá os cabeçalhos de resposta configurados com response_headers.
Consulte configuração para possíveis nomes de cabeçalhos.
session.info:set
sintaxe: session.info:set(key, value)
Define um valor no armazenamento de informações da sessão. O armazenamento de informações da sessão pode ser usado em cenários quando você deseja armazenar dados no armazenamento do lado do servidor, mas não deseja criar uma nova sessão e enviar um novo cookie de sessão. Os dados do armazenamento de informações não são considerados ao verificar a tag de autenticação ou o código de autenticação da mensagem. Assim, se você quiser usar isso para dados que precisam ser criptografados, precisa criptografar o valor antes de passá-lo para esta função.
local session, err, exists = require "resty.session".open()
if exists then
session.info:set("last-access", ngx.now())
session.info:save()
end
Com o armazenamento em cookie, isso ainda funciona, mas é quase o mesmo que session:set.
session.info:get
sintaxe: value = session.info:get(key)
Obtém um valor do armazenamento de informações da sessão.
local session, err, exists = require "resty.session".open()
if exists then
local last_access = session.info:get("last-access")
end
session.info:save
sintaxe: ok, err = session.info:save()
Salva informações. Apenas atualiza o armazenamento de backend. Não envia um novo cookie (exceto com armazenamento em cookie).
local session = require "resty.session".new()
session.info:set("last-access", ngx.now())
local ok, err = session.info:save()
Formato do Cookie
[ HEADER -------------------------------------------------------------------------------------]
[ Tipo || Flags || SID || Criado em || Deslocamento Rolante || Tamanho || Tag || Deslocamento de Inatividade || Mac ]
[ 1B || 2B || 32B || 5B || 4B || 3B || 16B || 3B || 16B ]
e
[ PAYLOAD --]
[ Dados *B ]
Tanto o HEADER quanto o PAYLOAD são codificados em base64 url antes de serem colocados em um cabeçalho Set-Cookie. Ao usar um armazenamento do lado do servidor, o PAYLOAD não é colocado no cookie. Com o armazenamento em cookie, o cabeçalho codificado em base64 url é concatenado com o payload codificado em base64 url.
O HEADER tem um tamanho fixo de 82 bytes binários ou 110 bytes em forma codificada em base64 url.
Campos do cabeçalho explicados:
- Tipo: número
1empacotado em um único byte little endian (atualmente o únicotiposuportado). - Flags: flags empacotadas em binário (curto) em uma forma de dois bytes little endian.
- SID:
32bytes de dados aleatórios criptográficos (ID da Sessão). - Criado em: segundos empacotados em binário desde a época em uma forma little endian, truncados para 5 bytes.
- Deslocamento Rolante: segundos empacotados em binário desde o tempo de criação em uma forma little endian (inteiro).
- Tamanho: tamanho dos dados empacotados em binário em uma forma de três bytes little endian.
- Tag:
16bytes da tag de autenticação da criptografia AES-256-GCM dos dados. - Deslocamento de Inatividade: segundos empacotados em binário desde o tempo de criação + deslocamento rolante em uma forma little endian, truncados para 3 bytes.
- Mac:
16bytes do código de autenticação da mensagem do cabeçalho.
Criptografia de Dados
- Material de chave inicial (IKM):
- derive IKM do
secrethashandosecretcom SHA-256, ou - use IKM de 32 bytes quando passado para a biblioteca com
ikm - Gere 32 bytes de id de sessão aleatório criptográfico (
sid) - Derive a chave de criptografia de 32 bytes e o vetor de inicialização de 12 bytes com HKDF usando SHA-256 (no modo FIPS, usa PBKDF2 com SHA-256).
- Use HKDF extract para derivar uma nova chave do
ikmpara obterkey(este passo pode ser feito apenas uma vez porikm):- comprimento da saída:
32 - digest:
"sha256" - key:
<ikm> - modo:
apenas extração - info:
"" - salt:
""
- comprimento da saída:
- Use HKDF expand para derivar
44bytes deoutput:- comprimento da saída:
44 - digest:
"sha256" - key:
<key> - modo:
apenas expansão - info:
"encryption:<sid>" - salt:
""
- comprimento da saída:
- Os primeiros 32 bytes de
outputsão a chave de criptografia (aes-key), e os últimos 12 bytes são o vetor de inicialização (iv). - Criptografe
plaintext(JSON codificado e opcionalmente desinflado) usando AES-256-GCM para obterciphertextetag. - cipher:
"aes-256-gcm" - key:
<aes-key> - iv:
<iv> - plaintext:
<plaintext> - aad: use os primeiros 47 bytes do
headercomoaad, que inclui:- Tipo
- Flags
- ID da Sessão
- Hora de Criação
- Deslocamento Rolante
- Tamanho dos Dados
Há uma variação para cookies remember no passo 3, onde podemos usar PBKDF2 em vez de HKDF, dependendo da configuração de remember_safety (também a usamos no modo FIPS). As configurações de PBKDF2:
- comprimento da saída:
44 - digest:
"sha256" - senha:
<key> - salt:
"encryption:<sid>" - iterações:
<1000|10000|100000|1000000> - pkcs5:
1(compatível com FIPS em nosso caso de uso, mas é necessário desabilitar as verificações baseadas emSP800-132, como contagem de iterações, veja: https://docs.openssl.org/master/man7/provider-kdf/#kdf-parameters)
As contagens de iterações são baseadas na configuração de remember_safety ("Low", "Medium", "High", "Very High"), se remember_safety estiver definido como "None", usaremos o HDKF como acima.
Nota: Para compatibilidade com versões anteriores, desabilitamos as verificações de conformidade do SP800-132 no modo FIPS. Essas verificações garantem que o comprimento do salt seja de pelo menos 128 bits, o comprimento da chave derivada seja de pelo menos 112 bits e que a contagem de iterações seja de pelo menos 1000. Essas verificações estão desabilitadas por padrão no provedor padrão do OpenSSL, mas estão habilitadas por padrão no provedor FIPS.
Autenticação do Cabeçalho do Cookie
- Derive a chave de autenticação de 32 bytes (
mac_key) com HKDF usando SHA-256 (no modo FIPS, usa PBKDF2 com SHA-256):- Use HKDF extract para derivar uma nova chave do
ikmpara obterkey(este passo pode ser feito apenas uma vez porikme reutilizado com a geração da chave de criptografia):- comprimento da saída:
32 - digest:
"sha256" - key:
<ikm> - modo:
apenas extração - info:
"" - salt:
""
- comprimento da saída:
- Use HKDF expand para derivar
32bytes demac-key:- comprimento da saída:
32 - digest:
"sha256" - key:
<key> - modo:
apenas expansão - info:
"authentication:<sid>" - salt:
""
- comprimento da saída:
- Use HKDF extract para derivar uma nova chave do
- Calcule o código de autenticação da mensagem usando HMAC-SHA256:
- digest:
"sha256" - key:
<mac-key> - message: use os primeiros 66 bytes do
header, que inclui:- Tipo
- Flags
- ID da Sessão
- Hora de Criação
- Deslocamento Rolante
- Tamanho dos Dados
- Tag
- Deslocamento de Inatividade
Interface de Armazenamento Personalizado
Se você deseja implementar um armazenamento personalizado, precisa implementar a seguinte interface:
---
-- <custom> backend para biblioteca de sessão
--
-- @module <custom>
---
-- Armazenamento
-- @section instance
local metatable = {}
metatable.__index = metatable
function metatable.__newindex()
error("tentativa de atualizar uma tabela somente leitura", 2)
end
---
-- Armazena dados da sessão.
--
-- @function instance:set
-- @tparam string name nome do cookie
-- @tparam string key chave da sessão
-- @tparam string value valor da sessão
-- @tparam number ttl tempo de vida da sessão
-- @tparam number current_time tempo atual
-- @tparam[opt] string old_key id da sessão antiga
-- @tparam string stale_ttl tempo de vida antiga
-- @tparam[opt] table metadata tabela de metadados
-- @treturn true|nil ok
-- @treturn string mensagem de erro
function metatable:set(name, key, value, ttl, current_time, old_key, stale_ttl, metadata)
-- NYI
end
---
-- Recupera dados da sessão.
--
-- @function instance:get
-- @tparam string name nome do cookie
-- @tparam string key chave da sessão
-- @treturn string|nil dados da sessão
-- @treturn string mensagem de erro
function metatable:get(name, key)
-- NYI
end
---
-- Deleta dados da sessão.
--
-- @function instance:delete
-- @tparam string name nome do cookie
-- @tparam string key chave da sessão
-- @tparam[opt] table metadata metadados da sessão
-- @treturn boolean|nil dados da sessão
-- @treturn string mensagem de erro
function metatable:delete(name, key, current_time, metadata)
-- NYI
end
local storage = {}
---
-- Construtores
-- @section constructors
---
-- Configuração
-- @section configuration
---
-- Configuração de armazenamento <custom>
-- @field <field-name> TBD
-- @table configuration
---
-- Cria um armazenamento <custom>.
--
-- Isso cria uma nova instância de armazenamento em memória compartilhada.
--
-- @function module.new
-- @tparam[opt] table configuration armazenamento <custom> @{configuration}
-- @treturn table instância de armazenamento <custom>
function storage.new(configuration)
-- NYI
-- return setmetatable({}, metatable)
end
return storage
Consulte as implementações existentes para os detalhes. E, por favor, faça um pull-request para que possamos integrá-lo diretamente à biblioteca para outros usuários também.
GitHub
Você pode encontrar dicas adicionais de configuração e documentação para este módulo no repositório GitHub para nginx-module-session.