مقدمة في OAuth 2.0 و JWT على PHP
\nتتجه تطبيقات الويب الحديثة بشكل متزايد بعيدًا عن المصادقة التقليدية القائمة على الجلسات نحو حلول أكثر مرونة وقابلية للتوسع. أصبح بروتوكولان رئيسيان — OAuth 2.0 و JWT (JSON Web Tokens) — المعيار الفعلي للتفويض في REST API وتطبيقات الهاتف المحمول وهندسة الخدمات المصغرة. في هذه المقالة، سنشرح من خلال أمثلة عملية كيفية تنفيذ OAuth 2.0 و JWT التفويض على PHP باستخدام المكتبات الحديثة وأفضل ممارسات الأمان.
\nستتعلم كيفية إعداد خادم التفويض، وإصدار رموز JWT والتحقق منها، وتنظيم إصدار رموز التحديث، وحماية نقاط نهاية API الخاصة بك. جميع أمثلة الكود جاهزة للاستخدام في مشاريعك.
\n\nأساسيات بروتوكول OAuth 2.0
\nOAuth 2.0 هو بروتوكول تفويض يسمح للتطبيقات بالحصول على وصول محدود إلى موارد المستخدم دون نقل بيانات اعتماده. في سياق تطبيق PHP، يتم تنفيذ OAuth 2.0 عادةً من خلال منح رمز التفويض (Authorization Code Grant) أو منح كلمة المرور (Password Grant) للخدمات الخاصة.
\n\nالأدوار الرئيسية في OAuth 2.0
\n- \n
- مالك المورد — المستخدم الذي يمتلك البيانات \n
- العميل — التطبيق الذي يطلب الوصول (مثل واجهة PHP الأمامية الخاصة بك) \n
- خادم التفويض — الخادم الذي يصدر الرموز
- خادم المورد — الخادم الذي يوفر الموارد المحمية (API الخاص بك)
تدفق الحصول على الرمز عبر منح رمز التفويض
\n- \n
- ينتقل المستخدم إلى صفحة التفويض \n
- بعد تسجيل الدخول، يتم إعادة توجيه المستخدم مرة أخرى إلى التطبيق مع رمز مؤقت \n
- يقوم خادم PHP باستبدال الرمز بـ access_token و refresh_token \n
- يتم تنفيذ جميع الطلبات اللاحقة إلى API باستخدام الرأس
Authorization: Bearer <access_token>\n
تنفيذ JWT على PHP باستخدام مكتبة firebase/php-jwt
\nللعمل مع JWT في PHP، سنستخدم المكتبة الشهيرة firebase/php-jwt. سنقوم بتثبيتها عبر Composer:
composer require firebase/php-jwt\n\nتوليد رمز JWT
\nسننشئ دالة لإصدار رمز وصول مع الحمولة (claims):
\n<?php\nuse Firebase\\JWT\\JWT;\nuse Firebase\\JWT\\Key;\n\nfunction generateAccessToken(int $userId, string $email): string {\n $secretKey = 'your-256-bit-secret-key-here';\n $issuedAt = time();\n $expirationTime = $issuedAt + 3600; // 1 ساعة\n\n $payload = [\n 'iss' => 'pythonlib.ru',\n 'iat' => $issuedAt,\n 'exp' => $expirationTime,\n 'sub' => $userId,\n 'email' => $email,\n 'roles' => ['user']\n ];\n\n return JWT::encode($payload, $secretKey, 'HS256');\n}\n\nالتحقق من رمز JWT
\nالتحقق من صحة الرمز مع كل طلب إلى مورد محمي:
\n<?php\nfunction validateAccessToken(string $token): ?object {\n $secretKey = 'your-256-bit-secret-key-here';\n try {\n $decoded = JWT::decode($token, new Key($secretKey, 'HS256'));\n return $decoded;\n } catch (\\Exception $e) {\n // الرمز منتهي الصلاحية، غير صالح، أو التوقيع غير متطابق\n return null;\n }\n}\n\nالوسيط (Middleware) للتحقق من JWT
\nمثال على وسيط بسيط يمكن استخدامه مع أي إطار عمل:
\n<?php\nfunction authMiddleware(): ?object {\n $headers = getallheaders();\n $authHeader = $headers['Authorization'] ?? '';\n\n if (!preg_match('/Bearer\\s(\\S+)/', $authHeader, $matches)) {\n http_response_code(401);\n echo json_encode(['error' => 'الرمز غير مقدم']);\n exit;\n }\n\n $token = $matches[1];\n $user = validateAccessToken($token);\n\n if (!$user) {\n http_response_code(401);\n