Autorização e Autenticação em Rust: do JWT às Sessões
No mundo da programação de sistemas e web, o Rust conquistou a reputação de ser uma linguagem segura e rápida. No entanto, ao criar aplicações web, os desenvolvedores frequentemente enfrentam a tarefa de implementar autenticação (verificação da identidade do usuário) e autorização (verificação de permissões de acesso). Neste artigo, exploraremos as principais bibliotecas e abordagens para implementar esses mecanismos em Rust, além de fornecer exemplos práticos de código.
Conceitos Fundamentais de Autenticação e Autorização
Antes de passarmos para as ferramentas, é importante diferenciar os conceitos:
- Autenticação — o processo de verificar se o usuário é quem ele diz ser. Geralmente é feito com login/senha, tokens ou biometria.
- Autorização — a determinação de quais recursos e ações estão disponíveis para um usuário autenticado. Frequentemente implementada através de funções (administrador, moderador, usuário) ou permissões de acesso.
Em Rust, ambos os processos podem ser implementados tanto em baixo nível (gerenciamento manual de tokens) quanto com a ajuda de bibliotecas prontas.
Bibliotecas Populares para Autenticação em Rust
Para trabalhar com sessões e tokens em Rust, existem várias soluções maduras:
actix-identity— para gerenciamento de sessões no framework web Actix-web. Suporta sessões baseadas em cookies e Redis.jsonwebtoken— biblioteca para trabalhar com JWT (JSON Web Tokens). Permite criar, assinar e verificar tokens.argon2— implementação do algoritmo de hash de senhas Argon2, recomendado pela OWASP.bcrypt— biblioteca clássica para hash de senhas.
Abaixo, veremos cada ferramenta com exemplos.
Exemplo 1: Autenticação com JWT e jsonwebtoken
JWT é uma das formas mais populares de autenticação em APIs REST. O token contém declarações (claims) e é assinado com uma chave secreta. Vamos ver uma implementação básica usando a biblioteca jsonwebtoken.
// cargo add jsonwebtoken serdeuse jsonwebtoken::{encode, decode, Header, Validation, EncodingKey, DecodingKey};use serde::{Serialize, Deserialize};
#[derive(Debug, Serialize, Deserialize)]struct Claims { sub: String, // identificador do usuário exp: usize, // tempo de expiração (timestamp UNIX) role: String, // função do usuário}
fn create_token(user_id: &str, role: &str) -> Result<String, jsonwebtoken::errors::Error> { let claims = Claims { sub: user_id.to_owned(), exp: (chrono::Utc::now() + chrono::Duration::hours(24)).timestamp() as usize, role: role.to_owned(), }; encode( &Header::default(), &claims, &EncodingKey::from_secret(b"sua_chave_secreta") )}
fn verify_token(token: &str) -> Result<Claims, jsonwebtoken::errors::Error> { let token_data = decode::<Claims>( token, &DecodingKey::from_secret(b"sua_chave_secreta"), &Validation::default() )?; Ok(token_data.claims)}Neste exemplo, criamos um token com validade de 24 horas contendo o ID do usuário e sua função. A função verify_token verifica a assinatura e retorna as claims, que podem ser usadas para autorização.
Exemplo 2: Hash de Senhas com Argon2
Nunca armazene senhas em texto puro! Use Argon2 — um algoritmo de hash moderno e seguro.
// cargo add argon2use argon2::{Argon2, PasswordHash, PasswordHasher, PasswordVerifier};use argon2::password_hash::{SaltString, rand_core::OsRng};
fn hash_password(password: &str) -> String { let salt = SaltString::generate(&mut OsRng); let argon2 = Argon2::default(); argon2.hash_password(password.as_bytes(), &salt) .expect("Erro de hash")