مقدمة في OAuth 2.0 و JWT على PHP
\n\nنادرًا ما تخلو تطبيقات الويب الحديثة من أنظمة التفويض. البروتوكولان الأكثر شيوعًا — OAuth 2.0 و JWT (JSON Web Token) — يسمحان للمطورين بإنشاء حلول آمنة وقابلة للتوسع. في هذه المقالة، سنشرح كيفية تنفيذ تفويض OAuth 2.0 و JWT على PHP من الصفر. المحتوى موجه للمبتدئين، لذلك سيتم شرح جميع المفاهيم بلغة بسيطة مع أمثلة عملية.
\n\nOAuth 2.0 هو بروتوكول وصول مفوض. يسمح للمستخدمين بمنح أطراف ثالثة وصولًا محدودًا إلى مواردهم دون مشاركة كلمة المرور. JWT، بدوره، هو تنسيق رمز مضغوط يحتوي على جميع المعلومات الضرورية حول المستخدم وصلاحياته.
\n\nما هو JWT وكيف يعمل؟
\n\nJWT (JSON Web Token) هو معيار مفتوح (RFC 7519) يحدد طريقة مضغوطة ومكتفية ذاتيًا لنقل المعلومات بين الأطراف في شكل كائن JSON. يتكون الرمز من ثلاثة أجزاء مفصولة بنقاط:
\n\n- \n
- Header — يحتوي على معلومات حول نوع الرمز وخوارزمية التشفير (عادةً HS256 أو RS256). \n
- Payload — يحتوي على "المطالبات" (claims): بيانات المستخدم، وقت الإصدار (iat)، وقت الانتهاء (exp) وغيرها. \n
- Signature — توقيع تم إنشاؤه بناءً على header و payload والمفتاح السري. يضمن سلامة البيانات. \n
إليك كيف يبدو JWT النموذجي:
\n\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6ItCQ0L3QsNGC0L7Qu9C40LkiLCJpYXQiOjE1MTYyMzkwMjJ9.4vGJ7qF6b0Q9l8z3X5p2Rk1h7t9y2w4z6x8c0v2b4n6m8\n\nميزة JWT هي أن الخادم لا يحتاج إلى تخزين الجلسات في قاعدة البيانات — جميع المعلومات مشفرة بالفعل في الرمز. هذا يجعل النظام قابلًا للتوسع بسهولة.
\n\nتثبيت مكتبة العمل مع JWT في PHP
\n\nللعمل مع JWT في PHP، سنستخدم المكتبة الشائعة firebase/php-jwt. قم بتثبيتها عبر Composer:
composer require firebase/php-jwt\n\nإنشاء والتحقق من رمز JWT
\n\nلننظر إلى مثال أساسي لإنشاء رمز عند تسجيل دخول المستخدم والتحقق منه عند طلب مورد محمي.
\n\n1. توليد الرمز (login.php):
\n\n<?php\nrequire_once 'vendor/autoload.php';\n\nuse Firebase\\JWT\\JWT;\nuse Firebase\\JWT\\Key;\n\n$secretKey = 'مفتاحك-السري-بطول-لا-يقل-عن-32-حرفًا';\n\n// بيانات المستخدم بعد المصادقة الناجحة\n$payload = [\n 'iss' => 'pythonlib.ru', // ناشر الرمز\n 'sub' => $userId, // معرف المستخدم\n 'name' => $userName, // اسم المستخدم\n 'role' => 'user', // الدور\n 'iat' => time(), // وقت الإصدار\n 'exp' => time() + 3600 // الرمز ينتهي بعد ساعة واحدة\n];\n\n$jwt = JWT::encode($payload, $secretKey, 'HS256');\n\n// إرسال الرمز إلى العميل\necho json_encode(['token' => $jwt]);\n?>\n\n2. التحقق من الرمز (profile.php):
\n\n<?php\nrequire_once 'vendor/autoload.php';\n\nuse Firebase\\JWT\\JWT;\nuse Firebase\\JWT\\Key;\n\n$secretKey = 'مفتاحك-السري-بطول-لا-يقل-عن-32-حرفًا';\n\n// الحصول على الرمز من رأس Authorization\n$headers = getallheaders();\n$authHeader = $headers['Authorization'] ?? '';\n\nif (preg_match('/Bearer\\s(\\S+)/', $authHeader, $matches)) {\n $jwt = $matches[1];\n \n try {\n $decoded = JWT::decode($jwt, new Key($secretKey, 'HS256'));\n \n // الرمز صالح، الحصول على بيانات المستخدم\n $userId = $decoded->sub;\n $userName = $decoded->name;\n \n // إرجاع البيانات المحمية\n echo json_encode(['status' => 'success', 'user' => $decoded]);\n \n } catch (Exception $e) {\n // الرمز غير صالح أو منتهي الصلاحية\n htt