Autorização e Autenticação em Rust: Guia Completo para Desenvolvedores
Rust é uma linguagem de programação de sistemas que está ganhando popularidade para a criação de serviços web seguros e de alta carga. No entanto, implementar autenticação (verificação de identidade) e autorização (verificação de permissões de acesso) em Rust requer uma abordagem especial devido ao seu sistema de tipos rigoroso e à falta de soluções integradas. Neste artigo, abordaremos as principais bibliotecas e exemplos práticos.
Por que Rust para Autenticação?
Segurança é a principal prioridade do Rust. O compilador previne vazamentos de memória, condições de corrida e muitas vulnerabilidades comuns em C/C++. No entanto, implementar autenticação manualmente pode levar a erros, por isso a comunidade criou várias bibliotecas maduras.
Principais Bibliotecas para Autenticação em Rust
1. actix-web-httpauth — para o framework web Actix-web
A biblioteca mais popular para implementar autenticação HTTP (Basic, Bearer, Digest) no ecossistema Actix-web.
2. jsonwebtoken — Trabalhando com JWT
Implementação completa de JSON Web Tokens (JWT) para Rust. Suporta RS256, HS256, ES256 e outros algoritmos.
3. bcrypt — Hash de Senhas
Biblioteca confiável para hash de senhas com o algoritmo bcrypt e geração automática de salt.
4. argon2 — Hash Moderno
Se o bcrypt parecer desatualizado, use o Argon2 — vencedor da competição Password Hashing Competition.
5. tower-http — Middleware para Autorização
Permite criar middleware reutilizável para verificar permissões de acesso em qualquer servidor HTTP baseado em Tower.
Exemplo Prático: Autenticação via JWT no Actix-web
Vamos considerar um exemplo mínimo de servidor com registro e login. Primeiro, adicione as dependências no Cargo.toml:
[dependencies]actix-web = "4"actix-web-httpauth = "0.8"jsonwebtoken = "9"bcrypt = "0.15"serde = { version = "1", features = ["derive"] }tokio = { version = "1", features = ["full"] }Agora, vamos escrever a estrutura do usuário e as funções para criar/verificar JWT:
use actix_web::{web, App, HttpServer, HttpResponse, HttpRequest};use actix_web_httpauth::extractors::bearer::BearerAuth;use jsonwebtoken::{encode, decode, Header, Validation, EncodingKey, DecodingKey};use bcrypt::{hash, verify, DEFAULT_COST};use serde::{Serialize, Deserialize};
#[derive(Debug, Serialize, Deserialize)]struct Claims { sub: String, // email do usuário exp: usize, // tempo de expiração do token}
#[derive(Debug, Serialize, Deserialize)]struct User { email: String, password_hash: String,}
// Armazenamento de usuários (na prática, um banco de dados)static USERS: once_cell::sync::Lazy<std::sync::Mutex<Vec<User>>> = once_cell::sync::Lazy::new(|| std::sync::Mutex::new(vec![]));
async fn register(info: web::Json<UserInput>) -> HttpResponse { let hashed = hash(&info.password, DEFAULT_COST).unwrap(); let user = User { email: info.email.clone(), password_hash: hashed, }; USERS.lock().unwrap().push(user); HttpResponse::Ok().json("User registered")}
async fn login(info: web::Json<UserInput>) -> HttpResponse { let users = USERS.lock().unwrap(); if let Some(user) = users.iter().find(|u| u.email == info.email) { if verify(&info.password, &user.password_hash).unwrap() { let claims = Claims { sub: info.email.clone(), exp: 10000000000, }; let token = encode( &Header::default(), &claims, &EncodingKey::from_secret(b"secret_key"), ).unwrap(); return HttpResponse::Ok().json(token); } } HttpResponse::Unauthorized