Autorisierung und Authentifizierung in Rust: vollständiger Leitfaden für Entwickler
Rust ist eine systemnahe Programmiersprache, die für die Erstellung hochleistungsfähiger und sicherer Webdienste immer beliebter wird. Die Implementierung von Authentifizierung (Identitätsprüfung) und Autorisierung (Zugriffsrechteprüfung) in Rust erfordert jedoch aufgrund des strengen Typsystems und des Fehlens integrierter Lösungen einen besonderen Ansatz. In diesem Artikel behandeln wir die wichtigsten Bibliotheken und praktische Beispiele.
Warum Rust für die Authentifizierung?
Sicherheit hat bei Rust höchste Priorität. Der Compiler verhindert Speicherlecks, Datenrennen und viele Schwachstellen, die für C/C++ typisch sind. Die manuelle Implementierung der Authentifizierung kann jedoch zu Fehlern führen, weshalb die Community mehrere ausgereifte Bibliotheken entwickelt hat.
Wichtige Bibliotheken für die Authentifizierung in Rust
1. actix-web-httpauth — für das Web-Framework Actix-web
Die beliebteste Bibliothek zur Implementierung von HTTP-Authentifizierung (Basic, Bearer, Digest) im Actix-web-Ökosystem.
2. jsonwebtoken — Arbeit mit JWT
Vollständige Implementierung von JSON Web Tokens (JWT) für Rust. Unterstützt RS256, HS256, ES256 und andere Algorithmen.
3. bcrypt — Passwort-Hashing
Zuverlässige Bibliothek zum Hashen von Passwörtern mit dem bcrypt-Algorithmus und automatischer Salt-Generierung.
4. argon2 — modernes Hashing
Wenn bcrypt veraltet erscheint, verwenden Sie Argon2 – den Gewinner des Password Hashing Competition.
5. tower-http — Middleware für Autorisierung
Ermöglicht die Erstellung wiederverwendbarer Middleware zur Zugriffsrechteprüfung in jedem HTTP-Server auf Basis von Tower.
Praktisches Beispiel: Authentifizierung mit JWT in Actix-web
Betrachten wir ein minimales Beispiel eines Servers mit Registrierung und Login. Fügen Sie zunächst die Abhängigkeiten in Cargo.toml hinzu:
[dependencies]actix-web = "4"actix-web-httpauth = "0.8"jsonwebtoken = "9"bcrypt = "0.15"serde = { version = "1", features = ["derive"] }tokio = { version = "1", features = ["full"] }Schreiben wir nun die Benutzerstruktur und Funktionen zum Erstellen/Überprüfen von 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, // E-Mail des Benutzers exp: usize, // Ablaufzeit des Tokens}
#[derive(Debug, Serialize, Deserialize)]struct User { email: String, password_hash: String,}
// Benutzerspeicher (in der Praxis – Datenbank)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::Unauthori