التفويض والمصادقة في Rust: دليل شامل للمطورين
Rust هي لغة برمجة أنظمة تكتسب شعبية متزايدة لبناء خدمات ويب عالية الأداء وآمنة. ومع ذلك، فإن تنفيذ المصادقة (التحقق من الهوية) والتفويض (التحقق من صلاحيات الوصول) في Rust يتطلب نهجًا خاصًا بسبب نظام الأنواع الصارم وغياب الحلول المدمجة. في هذه المقالة، سنستعرض المكتبات الرئيسية والأمثلة العملية.
لماذا Rust للمصادقة؟
الأمان هو الأولوية القصوى في Rust. يمنع المترجم تسرب الذاكرة، وسباقات البيانات، والعديد من الثغرات الشائعة في C/C++. ومع ذلك، فإن تنفيذ المصادقة يدويًا قد يؤدي إلى أخطاء، لذلك أنشأ المجتمع العديد من المكتبات الناضجة.
المكتبات الرئيسية للمصادقة في Rust
1. actix-web-httpauth — لإطار العمل Actix-web
المكتبة الأكثر شيوعًا لتنفيذ مصادقة HTTP (Basic، Bearer، Digest) في نظام Actix-web البيئي.
2. jsonwebtoken — العمل مع JWT
تنفيذ كامل لـ JSON Web Tokens (JWT) في Rust. يدعم خوارزميات RS256، HS256، ES256 وغيرها.
3. bcrypt — تجزئة كلمات المرور
مكتبة موثوقة لتجزئة كلمات المرور باستخدام خوارزمية bcrypt مع توليد تلقائي للملح.
4. argon2 — التجزئة الحديثة
إذا كنت تعتقد أن bcrypt قديم، استخدم Argon2 — الفائز في مسابقة Password Hashing Competition.
5. tower-http — middleware للتفويض
يسمح بإنشاء middleware قابلة لإعادة الاستخدام للتحقق من صلاحيات الوصول في أي خادم HTTP يعتمد على Tower.
مثال عملي: المصادقة عبر JWT في Actix-web
لننظر في مثال بسيط لخادم مع التسجيل وتسجيل الدخول. أولاً، أضف التبعيات في 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"] }الآن، لنكتب بنية المستخدم ودوال إنشاء/التحقق من 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, // البريد الإلكتروني للمستخدم exp: usize, // وقت انتهاء صلاحية الرمز}
#[derive(Debug, Serialize, Deserialize)]struct User { email: String, password_hash: String,}
// مخزن المستخدمين (في الواقع — قاعدة بيانات)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