مقدمة: لماذا OAuth 2.0 و JWT في Rust؟
\n\nنادرًا ما تستغني تطبيقات الويب الحديثة عن نظام المصادقة والتفويض. OAuth 2.0 هو المعيار الصناعي لتفويض الوصول، و JWT (JSON Web Tokens) هي طريقة مضغوطة وآمنة لنقل الادعاءات بين الأطراف. Rust، بفضل أدائها وأمان الذاكرة، أصبحت أكثر شيوعًا لإنشاء خوادم عالية التحميل. في هذه المقالة، سنشرح عمليًا كيفية تنفيذ تفويض OAuth 2.0 مع JWT في Rust باستخدام الكريتات الشائعة والأساليب الحديثة.
\n\n1. إعداد المشروع وتثبيت التبعيات
\n\nلنبدأ بإنشاء مشروع جديد في Rust وإضافة التبعيات اللازمة. سنستخدم actix-web لخادم الويب، jsonwebtoken للعمل مع JWT، serde للتسلسل، و reqwest لطلبات HTTP إلى موفري OAuth الخارجيين.
# Cargo.toml\n[package]\nname = "oauth-jwt-rust"\nversion = "0.1.0"\nedition = "2021"\n\n[dependencies]\nactix-web = "4"\nactix-rt = "2"\njsonwebtoken = "9"\nserde = { version = "1.0", features = ["derive"] }\nserde_json = "1.0"\nreqwest = { version = "0.12", features = ["json"] }\ntokio = { version = "1", features = ["full"] }\ndotenv = "0.15"\nchrono = { version = "0.4", features = ["serde"] }\nuuid = { version = "1", features = ["v4"] }\n\nلننشئ ملف .env لتخزين المفاتيح السرية:
JWT_SECRET=your_super_secret_key_here\nGITHUB_CLIENT_ID=your_github_client_id\nGITHUB_CLIENT_SECRET=your_github_client_secret\n\n2. الهيكل الأساسي لرموز JWT
\n\nيتكون JWT من ثلاثة أجزاء: الرأس، الحمولة، والتوقيع. سنحدد الهياكل للعمل مع الرموز.
\n\n// src/jwt.rs\nuse chrono::{Utc, Duration};\nuse jsonwebtoken::{encode, decode, Header, Validation, EncodingKey, DecodingKey};\nuse serde::{Deserialize, Serialize};\n\n#[derive(Debug, Serialize, Deserialize)]\npub struct Claims {\n pub sub: String, // معرف المستخدم\n pub email: String, // البريد الإلكتروني للمستخدم\n pub exp: usize, // وقت الانتهاء\n pub iat: usize, // وقت الإصدار\n}\n\npub fn create_jwt(user_id: &str, email: &str) -> Result {\n let now = Utc::now();\n let expiration = now + Duration::hours(24); // الرمز صالح لمدة 24 ساعة\n\n let claims = Claims {\n sub: user_id.to_string(),\n email: email.to_string(),\n exp: expiration.timestamp() as usize,\n iat: now.timestamp() as usize,\n };\n\n let secret = std::env::var("JWT_SECRET").expect("JWT_SECRET must be set");\n encode(\n &Header::default(),\n &claims,\n &EncodingKey::from_secret(secret.as_bytes()),\n )\n}\n\npub fn validate_jwt(token: &str) -> Result {\n let secret = std::env::var("JWT_SECRET").expect("JWT_SECRET must be set");\n let token_data = decode::(\n token,\n &DecodingKey::from_secret(secret.as_bytes()),\n &Validation::default(),\n )?;\n Ok(token_data.claims)\n} \n\n3. تنفيذ OAuth 2.0 مع GitHub
\n\nلننظر في السيناريو الكلاسيكي لـ OAuth 2.0 — التفويض عبر GitHub. يتم توجيه المستخدم إلى GitHub، وبعد التأكيد يحصل على رمز نستبدله بـ access token.
\n\n3.1. نقطة النهاية لبدء تدفق OAuth
\n\n// src/oauth.rs\nuse actix_web::{web, HttpResponse, HttpRequest};\nuse reqwest::Client;\nuse serde_json::Value;\n\npub async fn github_login() -> HttpResponse {\n let client_id = std::env::var("GITHUB_CLIENT_ID").unwrap();\n let redirect_uri = "http://localhost:8080/auth/github/callback";\n \n let auth_url = format!(\n "https://github.com/login/oauth/authorize?client_id={}&redirect_uri={}&scope=user:email",\n client_id, redirect_uri\n );\n \n HttpRes