موضع نص الإشعار اتصل بنا تفضل الآن!

مقارنتي بين طرق الـ Authentication المختلفة (Passport, Sanctum, JWT) في مشاريع Laravel واقعيا

George Bahgat


لماذا يعد اختيار طريقة المصادقة (Authentication) قرارًا حاسمًا في مشاريع Laravel؟

عندما بدأت أول مشروع حقيقي باستخدام Laravel، ظننت أن المصادقة مجرد "تسجيل دخول وتسجيل خروج"، وأن أي طريقة ستعمل بنفس الكفاءة. لكن بعد أسابيع من التعديل والتصحيح والتعامل مع مشاكل أداء وتوافق بين الواجهة الأمامية والخلفية، أدركت أن اختيار آلية المصادقة ليس تفصيلًا تقنيًا بسيطًا، بل هو قرار استراتيجي يؤثر على كل جانب من جوانب التطبيق: من الأمان، إلى سهولة الصيانة، إلى تجربة المستخدم، وحتى سرعة التطوير.

في عالم Laravel، توجد ثلاث طرق شائعة جدًا للمصادقة في المشاريع الحديثة: Passport، Sanctum، وJWT (JSON Web Tokens). كل واحدة منها مبنية على فلسفة مختلفة، وتُناسب سيناريوهات استخدام محددة. وفي هذا المقال، سأشاركك تجربتي العملية مع كل طريقة، بما في ذلك الأكواد الفعلية التي استخدمتها، والمشاكل التي واجهتني، والفرق الحقيقي الذي لاحظته على أرض الواقع. الهدف ليس فقط مقارنة تقنية جافة، بل مساعدتك على اتخاذ القرار الصحيح لمشروعك القادم بناءً على سياقه الحقيقي، وليس على ما يُروّج له في المنتديات أو الفيديوهات السريعة.

الكلمات المفتاحية التي سنتناولها بشكل طبيعي في هذا المقال تشمل: مقارنة بين Passport وSanctum وJWT في Laravel، أفضل طريقة مصادقة لتطبيقات Laravel، استخدام Sanctum في تطبيقات SPA، تكامل Laravel مع JWT، وأمان تطبيقات Laravel باستخدام Passport. كل هذه المصطلحات ستظهر في سياقها الطبيعي، لأنها جزء من تجربة المطور اليومية.

ما الذي نبحث عنه حقًا في نظام مصادقة؟

قبل أن نغوص في التفاصيل التقنية، من المهم أن نتفق على المعايير التي نقيّم بها أي نظام مصادقة. من تجربتي، هذه النقاط الخمس هي الأهم:

  1. الأمان: هل يحمي بيانات المستخدم؟ هل يدعم التحديث التلقائي للـ tokens؟ هل يمنع هجمات مثل CSRF أو replay attacks؟
  2. البساطة والسرعة في التطوير: كم من الوقت يستغرق إعداده؟ هل يحتاج إلى تكوين معقد؟
  3. التوافق مع نوع المشروع: هل هو SPA؟ Mobile App؟ API عام؟ لوحة تحكم داخلية؟
  4. إدارة الجلسات ووقت الانتهاء (Expiration): كيف يتعامل مع تسجيل الخروج؟ هل يمكن إبطال رمز الوصول فورًا؟
  5. التوافق مع أدوات Laravel القياسية: هل يعمل بسلاسة مع Eloquent، Policies، Gates، وغيرها؟

في كل مرة جربت فيها إحدى الطرق الثلاث، كنت أقيّمها بناءً على هذه المعايير. ولن أكذب عليك: في بعض المشاريع، اضطررت لتغيير النظام بالكامل بعد أسبوعين من البدء، لأنني اخترت الحل "الشائع" بدلًا من الحل "المناسب".

Sanctum: البساطة التي لا تُقدّر بثمن

Sanctum هو الخيار الذي أبدأ به الآن في معظم مشاريعي الصغيرة والمتوسطة، خاصة تلك التي تعتمد على واجهة أمامية من نوع SPA (مثل Vue.js أو React) متصلة بواجهة Laravel API. السبب؟ لأنه ببساطة "يختفي" بعد الإعداد، ولا يُثقل المشروع بتعقيدات لا داعي لها.

كيف يعمل Sanctum في الواقع؟

Sanctum لا يعتمد على OAuth 2.0 مثل Passport، ولا يُصدر رموز JWT طويلة الأمد. بدلًا من ذلك، يستخدم مزيجًا ذكيًا من cookies وAPI tokens. إذا كنت تبني SPA متصلًا بنفس النطاق (أو subdomain)، فـ Sanctum يستخدم جلسة (session) تقليدية عبر cookies مع حماية CSRF تلقائية. أما إذا كنت تبني تطبيقًا خارجيًا (مثل تطبيق جوال)، فيمكنك إنشاء "Personal Access Token" ثابت يُرسل في header كل طلب.

في مشروع حديث لمنصة تعليمية، استخدمت Sanctum مع Vue.js كواجهة أمامية على نفس النطاق (app.example.com للواجهة، وapi.example.com للـ backend). الإعداد كان بسيطًا جدًا:

composer require laravel/sanctum
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
php artisan migrate

ثم في ملف app/Http/Kernel.php، أضفت middleware Sanctum إلى مجموعة api:

'api' => [
    \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
    'throttle:api',
    \Illuminate\Routing\Middleware\SubstituteBindings::class,
],

ومن ثم، في ملف config/sanctum.php، عدّلت stateful domains ليشمل النطاقات المسموح لها باستخدام الجلسات:

'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
    '%s%s',
    'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',
    env('APP_URL') ? ','.parse_url(env('APP_URL'), PHP_URL_HOST) : ''
))),

بعد ذلك، في ملف .env:

SANCTUM_STATEFUL_DOMAINS=app.example.com
SESSION_DOMAIN=.example.com

بهذا الإعداد، أصبحت الجلسات تعمل تلقائيًا بين الواجهة والـ API دون الحاجة لإرسال أي token في كل طلب. الـ CSRF token كان يُدار تلقائيًا عبر axios (أو أي مكتبة HTTP) إذا قمت بتهيئة الـ XSRF-TOKEN cookie بشكل صحيح.

نصيحة: إذا كنت تستخدم Sanctum مع SPA على نفس النطاق، تأكد من تعيين SESSION_DOMAIN بقيمة تبدأ بنقطة (مثل .example.com) حتى تُشارك الجلسة بين subdomains.

المشاكل التي واجهتني مع Sanctum

في أحد المشاريع، حاولت استخدام Sanctum مع تطبيق جوال (React Native). هنا ظهرت المشكلة: Sanctum لا يُصدر tokens قابلة للانتهاء تلقائيًا (مثل JWT). الـ Personal Access Tokens التي يولدها تكون "ثابتة" حتى يتم حذفها يدويًا. هذا يعني أنه لا يوجد "وقت انتهاء" افتراضي، مما يُضعف الأمان قليلًا.

الحل الذي اتبعته كان إنشاء عمود إضافي في جدول personal_access_tokens باسم expires_at، ثم كتابة middleware خاص يتحقق من هذا الحقل في كل طلب. لكن هذا يُضيف تعقيدًا يدويًا يُفقِد Sanctum ميزته الأساسية: البساطة.

لذلك، خلصت إلى قاعدة بسيطة: استخدم Sanctum إذا كان مشروعك SPA على نفس النطاق أو لوحة تحكم داخلية. أما إذا كنت تبني API عامًا أو تطبيقًا جوالًا، ففكّر في خيارات أخرى.

JWT: القوة والمرونة... مع ثمن باهظ

عندما سمعت لأول مرة عن JWT، بدو لي الحل السحري لكل مشاكل المصادقة: tokens خفيفة، لا تحتاج لتخزين في السيرفر، قابلة للتحقق منها رياضيًا، وتدعم الانتهاء التلقائي. لكن عندما طبّقته في مشروع حقيقي، اكتشفت أن "الاستقلالية" التي يوفرها JWT تأتي مع مسؤوليات أمان إضافية لا يمكن تجاهلها.

التجربة العملية مع JWT في Laravel

استخدمت مكتبة tymon/jwt-auth لأنها الأكثر انتشارًا في مجتمع Laravel. الإعداد كان أطول قليلًا من Sanctum:

composer require tymon/jwt-auth
php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"
php artisan jwt:secret

ثم عدّلت ملف config/auth.php لاستخدام guard خاص بـ JWT:

'guards' => [
    'api' => [
        'driver' => 'jwt',
        'provider' => 'users',
    ],
],

وبعد ذلك، في الـ controller، كان تسجيل الدخول كالتالي:

public function login(Request $request)
{
    $credentials = $request->only('email', 'password');

    if (! $token = auth()->attempt($credentials)) {
        return response()->json(['error' => 'Unauthorized'], 401);
    }

    return $this->respondWithToken($token);
}

protected function respondWithToken($token)
{
    return response()->json([
        'access_token' => $token,
        'token_type' => 'bearer',
        'expires_in' => auth()->factory()->getTTL() * 60
    ]);
}

كل طلب لاحق يحتاج إلى إرسال الـ token في header:

Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...

وهنا تبدأ التحديات الحقيقية.

المشاكل التي واجهتني مع JWT

أول مشكلة: لا يمكن إبطال الـ token بسهولة. لأن JWT stateless، بمجرد إصداره، يظل صالحًا حتى ينتهي وقته، حتى لو قام المستخدم بتسجيل الخروج! في مشروع تطبيق بنكي صغير، كان هذا كارثيًا من ناحية الأمان. الحل؟ إما تخزين الـ tokens في قاعدة البيانات (مما يلغي ميزة الـ stateless)، أو استخدام "قائمة سوداء" (blacklist) مؤقتة في Redis.

ثانيًا: التعامل مع الـ refresh tokens. إذا أردت تمديد جلسة المستخدم دون إعادة تسجيل الدخول، ستحتاج إلى إصدار زوج من الـ access token وrefresh token. هذا يُعقّد منطق الواجهة الأمامية، ويضيف طبقة أخرى من الأمان يجب حمايتها.

ثالثًا: التكامل مع ميزات Laravel القياسية. في Sanctum أو Passport، يمكنك استخدام auth()->user() أو $request->user() بشكل طبيعي. أما مع JWT، فغالبًا ستحتاج إلى كتابة middleware خاص أو الاعتماد على الـ guard اليدوي، مما قد يُربك المطورين الجدد في الفريق.

تحذير: JWT ليس "أكثر أمانًا" تلقائيًا. إذا لم تُشفّر البيانات الحساسة بشكل صحيح، أو إذا استخدمت secret key ضعيف، فقد يكون أضعف من جلسة تقليدية!

متى يكون JWT خيارًا مناسبًا؟

من تجربتي، JWT مناسب جدًا في سيناريوهات محددة:

  • عندما تحتاج إلى مصادقة عبر أنظمة متعددة (microservices) دون الاعتماد على قاعدة بيانات مركزية للجلسات.
  • عندما تريد تضمين بيانات المستخدم مباشرة في الـ token (مثل الـ roles) لتقليل عدد استعلامات قاعدة البيانات.
  • في تطبيقات الجوال التي تحتاج إلى جلسات طويلة الأمد مع تحكم دقيق في وقت الانتهاء.

لكن تذكّر دائمًا: هذه المرونة تأتي بثمن. أنت الآن مسؤول عن إدارة دورة حياة الـ token بالكامل.

Passport: القوة الكاملة لـ OAuth 2.0... لكن هل تحتاجها فعلاً؟

Passport هو الخيار الأثقل بين الثلاثة، لكنه أيضًا الأقوى من ناحية المعايير. إذا كنت تبني منصة تسمح لتطبيقات خارجية بالاتصال بها (مثل Twitter API أو Facebook Graph API)، فـ Passport هو الحل الأمثل. لكن إذا كنت تبني تطبيقًا داخليًا فقط، فقد تكون تُعقّد حياتك بلا داعٍ.

تجربتي في تطبيق منصة تكامل خارجي

في مشروع لمنصة SaaS، طلب منا السماح للعملاء بربط تطبيقاتهم الخاصة بواجهة API خاصة بنا. هنا، لم يكن أمامنا خيار سوى Passport. الإعداد كان كالتالي:

composer require laravel/passport
php artisan passport:install

ثم في ملف App/Models/User.php:

use Laravel\Passport\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens, Notifiable;
}

وفي AuthServiceProvider:

use Laravel\Passport\Passport;

public function boot()
{
    $this->registerPolicies();
    Passport::routes();
}

وأخيرًا، في config/auth.php:

'guards' => [
    'api' => [
        'driver' => 'passport',
        'provider' => 'users',
    ],
],

بعد ذلك، يمكن للعميل إنشاء "client" خاص به من لوحة التحكم، والحصول على client_id وclient_secret، ثم استخدام تدفق OAuth 2.0 (مثل Authorization Code Grant) للحصول على access token.

المشاكل التي واجهتني مع Passport

أول مشكلة: التعقيد الزائد. حتى لو كنت لا تحتاج إلى كل ميزات OAuth، فإن Passport يفرض عليك هيكلًا معينًا (جدول clients، personal_access_clients، إلخ). هذا يثقل قاعدة البيانات ويُعقّد عملية النسخ الاحتياطي والترحيل.

ثانيًا: التوافق مع SPA. Passport لا يدعم الجلسات عبر cookies بشكل افتراضي. إذا أردت استخدامه مع تطبيق Vue.js على نفس النطاق، ستحتاج إلى كتابة منطق مخصص لتخزين الـ token في localStorage أو sessionStorage، مما يُعرضك لهجمات XSS إذا لم تكن حذرًا.

ثالثًا: الأداء. كل طلب API مع Passport يتطلب استعلامًا إضافيًا لجدول oauth_access_tokens للتحقق من صلاحية الـ token. في Sanctum (مع الجلسات)، هذا لا يحدث. في JWT، لا يحدث أصلًا. هذا الفرق قد لا يُلاحظ في المشاريع الصغيرة، لكنه يصبح ملحوظًا جدًا عند التوسع.

حقيقة: 90% من المشاريع التي رأيتها تستخدم Passport لم تكن بحاجة فعلية إليه. Sanctum كان سيكفيها بسهولة.

هل Passport ميت؟

لا، Passport ليس ميتًا، لكن استخدامه يجب أن يكون مدروسًا. Laravel أصدر Sanctum خصيصًا لسد الفجوة بين البساطة (مثل الجلسات التقليدية) والقوة (مثل Passport). إذا لم تكن بحاجة إلى OAuth 2.0، فلا تستخدم Passport.

حتى Laravel نفسه يُوصي الآن باستخدام Sanctum لمعظم حالات الاستخدام، بما في ذلك SPA وتطبيقات الجوال البسيطة.

مقارنة عملية: جدول يلخّص الفروقات الجوهرية

بعد كل هذه التجارب، وضعت هذا الجدول ليساعدني (ويساعدك) في اتخاذ القرار بسرعة:

المعيار Sanctum JWT Passport
الاستخدام الأمثل SPA، لوحة تحكم داخلية Mobile Apps، Microservices API عام يدعم تطبيقات خارجية
الاعتماد على قاعدة البيانات نعم (لـ Personal Access Tokens) لا (إلا إذا استخدمت blacklist) نعم (لكل tokens وclients)
إبطال الـ token فورًا نعم (حذف من الجدول) لا (إلا عبر blacklist) نعم (حذف من الجدول)
التكامل مع Laravel ممتاز جيد (مع بعض التعديل) ممتاز
وقت الإعداد 5-10 دقائق 15-30 دقيقة 20-40 دقيقة

قصة واقعية: كيف غيّر اختيار المصادقة مصير مشروع كامل

في أحد المشاريع، كنا نبني تطبيقًا لإدارة المهام لفريق داخلي. في البداية، استخدمنا JWT لأن "الجميع يقول إنه الأفضل للأجهزة المحمولة". بعد شهر، بدأ الفريق يشكو من أن الجلسة تنتهي فجأة، وأنه لا يوجد طريقة لتسجيل الخروج من جميع الأجهزة دفعة واحدة. كما أننا اكتشفنا أن أحد المطورين كان يخزن الـ token في localStorage دون حماية كافية، مما عرّض التطبيق لهجوم XSS بسيط.

قرّرنا الهجرة إلى Sanctum. استغرق الأمر يومين: أعدنا هيكلة الـ auth routes، عدّلنا ملفات axios، وغيّرنا طريقة تخزين الجلسة. النتيجة؟

  • تسجيل الخروج أصبح فوريًا وشاملًا.
  • لم يعد هناك حاجة لـ refresh tokens.
  • التكامل مع Policies وGates أصبح طبيعيًا.
  • عدد الأخطاء المتعلقة بالمصادقة انخفض إلى الصفر.

الدرس الذي تعلمته؟ لا تتبع الاتجاهات، اتبع سياق مشروعك.

نصائح نهائية: كيف تختار الطريقة المناسبة لمشروعك؟

بعد كل هذه التجارب، إليك الخطوات التي أتبعها الآن قبل أن أبدأ أي مشروع:

  1. اسأل نفسك: هل سيتصل بهذا API تطبيقات خارجية؟ إذا كانت الإجابة نعم، فـ Passport هو خيارك. إذا لا، اذهب للخطوة التالية.
  2. هل الواجهة الأمامية على نفس النطاق أو subdomain؟ إذا نعم، Sanctum مع الجلسات هو الحل الأمثل. إذا لا (مثل تطبيق جوال مستقل)، فاختر بين Sanctum (بـ Personal Access Tokens) أو JWT حسب احتياجاتك في وقت الانتهاء.
  3. هل تحتاج إلى إبطال الجلسات فورًا؟ إذا كانت الإجابة نعم، تجنّب JWT إلا إذا كنت مستعدًا لبناء نظام blacklist.
  4. كم عدد المطورين في فريقك؟ إذا كان الفريق صغيرًا أو مبتدئًا، Sanctum سيوفر لك ساعات من الدعم والتصحيح.
تذكير: لا يوجد "أفضل" نظام مصادقة مطلق. الأفضل هو ما يناسب سياق مشروعك، فريقك، ومتطلباتك الأمنية.

الخاتمة: لا تُعقّد ما يمكن تبسيطه

في النهاية، المصادقة ليست هدفًا بحد ذاتها، بل وسيلة لحماية تطبيقك وتسهيل تجربة المستخدم. من تجربتي، أكثر الأخطاء شيوعًا تأتي من محاولة تطبيق حل "متطور" على مشكلة بسيطة. Sanctum، رغم بساطته، غطّى 80% من مشاريعي بفعالية وأمان. JWT كان ضروريًا في مشروعين فقط. أما Passport، فاستخدمته ثلاث مرات، وكل مرة كانت هناك حاجة حقيقية لـ OAuth 2.0.

لذا، قبل أن تكتب سطر كود واحد، خذ ورقة وقلم، واجب على الأسئلة السابقة. ثم ابدأ بـ Sanctum. إذا احتجت شيئًا أقوى لاحقًا، يمكنك دائمًا الترقية. لكن العكس (البدء بـ Passport ثم محاولة التبسيط) سيكون كابوسًا.

جرب، اختبر، وغيّر. لا تخف من العودة للخلف إذا اكتشفت أنك اخترت الطريق الخطأ. لأن في النهاية، التطبيق الناجح ليس الذي يستخدم أحدث التقنيات، بل الذي يحل المشكلة الصحيحة بالطريقة الصحيحة.

والآن، بعد أن قرأت كل هذا، اسأل نفسك: ما الطريقة التي سأستخدمها في مشروعي القادم؟ ولماذا؟ الإجابة ستكون بداية ذكية لمشروعك.

إرسال تعليق

الموافقة على ملفات تعريف الارتباط
”نحن نقدم ملفات تعريف الارتباط على هذا الموقع لتحليل حركة المرور وتذكر تفضيلاتك وتحسين تجربتك.“
لا يتوفر اتصال بالإنترنت!
”يبدو أن هناك خطأ ما في اتصالك بالإنترنت ، يرجى التحقق من اتصالك بالإنترنت والمحاولة مرة أخرى.“
تم الكشف عن مانع الإعلانات!
”لقد اكتشفنا أنك تستخدم مكونًا إضافيًا لحظر الإعلانات في متصفحك.
تُستخدم العائدات التي نحققها من الإعلانات لإدارة موقع الويب هذا ، ونطلب منك إدراج موقعنا في القائمة البيضاء في المكون الإضافي لحظر الإعلانات.“
Site is Blocked
Sorry! This site is not available in your country.