إطار Laravel

Laravel Sanctum ومصادقة API

18 دقيقة الدرس 27 من 45

Laravel Sanctum ومصادقة API

توفر Laravel Sanctum نظام مصادقة خفيف الوزن لتطبيقات SPA (تطبيقات الصفحة الواحدة)، وتطبيقات الهاتف المحمول، وواجهات برمجة التطبيقات البسيطة القائمة على الرموز. إنها توفر طريقة بسيطة لإصدار رموز API للمستخدمين ومصادقة الطلبات الواردة دون تعقيد OAuth.

ما هو Laravel Sanctum؟

يقدم Sanctum ميزتين متميزتين:

  • مصادقة SPA: مصادقة قائمة على الجلسة لتطبيقات الصفحة الواحدة المبنية بأطر عمل مثل Vue أو React أو Inertia
  • مصادقة رمز API: مصادقة قائمة على الرموز لتطبيقات الهاتف المحمول ومستهلكي API من الطرف الثالث
ملاحظة: لا يستخدم Sanctum رموز OAuth. بدلاً من ذلك، يستخدم رموز وصول شخصية بسيطة مخزنة في قاعدة البيانات الخاصة بك، مما يجعلها أبسط بكثير للتنفيذ والفهم.

التثبيت والإعداد

تتضمن لارافل Sanctum بشكل افتراضي في Laravel 8+. للإصدارات الأقدم، قم بالتثبيت عبر Composer:

# تثبيت Sanctum (إذا لم يكن مضمنًا بالفعل) composer require laravel/sanctum # نشر ملفات التكوين والترحيل php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider" # تشغيل الترحيلات لإنشاء جدول personal_access_tokens php artisan migrate

أضف middleware الخاص بـ Sanctum إلى مجموعة middleware الخاصة بـ API في app/Http/Kernel.php:

<?php namespace App\Http; use Illuminate\Foundation\Http\Kernel as HttpKernel; class Kernel extends HttpKernel { protected $middlewareGroups = [ 'api' => [ \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class, 'throttle:api', \Illuminate\Routing\Middleware\SubstituteBindings::class, ], ]; }

مصادقة رمز API

استخدم trait HasApiTokens في نموذج المستخدم الخاص بك:

<?php namespace App\Models; use Laravel\Sanctum\HasApiTokens; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; class User extends Authenticatable { use HasApiTokens, Notifiable; protected $fillable = [ 'name', 'email', 'password', ]; protected $hidden = [ 'password', 'remember_token', ]; }

إصدار رموز API

أنشئ نقطة نهاية تصدر الرموز بعد مصادقة المستخدمين:

<?php namespace App\Http\Controllers\Api; use App\Http\Controllers\Controller; use App\Models\User; use Illuminate\Http\Request; use Illuminate\Support\Facades\Hash; use Illuminate\Validation\ValidationException; class AuthController extends Controller { public function login(Request $request) { $request->validate([ 'email' => 'required|email', 'password' => 'required', 'device_name' => 'required', ]); $user = User::where('email', $request->email)->first(); if (!$user || !Hash::check($request->password, $user->password)) { throw ValidationException::withMessages([ 'email' => ['بيانات الاعتماد المقدمة غير صحيحة.'], ]); } // إنشاء رمز للمستخدم $token = $user->createToken($request->device_name)->plainTextToken; return response()->json([ 'token' => $token, 'user' => $user, ]); } public function logout(Request $request) { // إلغاء رمز المستخدم الحالي $request->user()->currentAccessToken()->delete(); return response()->json([ 'message' => 'تم تسجيل الخروج بنجاح', ]); } public function logoutAll(Request $request) { // إلغاء جميع رموز المستخدم $request->user()->tokens()->delete(); return response()->json([ 'message' => 'تم تسجيل الخروج من جميع الأجهزة بنجاح', ]); } }

قدرات الرمز (الأذونات)

قم بتعيين قدرات محددة للرموز للتحكم الدقيق في الوصول:

<?php // إنشاء رمز بقدرات محددة $token = $user->createToken('mobile-app', [ 'post:create', 'post:update', 'post:delete', ])->plainTextToken; // إنشاء رمز للقراءة فقط $token = $user->createToken('analytics', [ 'post:read', 'user:read', ])->plainTextToken; // في المتحكم الخاص بك، تحقق مما إذا كان الرمز لديه قدرة محددة public function store(Request $request) { if (!$request->user()->tokenCan('post:create')) { return response()->json([ 'message' => 'غير مصرح' ], 403); } // إنشاء المنشور... } // أو استخدم middleware Route::post('/posts', [PostController::class, 'store']) ->middleware('ability:post:create'); Route::get('/posts', [PostController::class, 'index']) ->middleware('ability:post:read,post:create'); // يمكن أن يكون لديه أي من القدرتين
نصيحة: يتم تخزين قدرات الرمز في قاعدة البيانات، لذا يمكنك إنشاءها والتحقق منها وإلغاؤها في أي وقت دون تغيير الكود الخاص بك.

حماية المسارات

استخدم middleware auth:sanctum لحماية مسارات API:

<?php // routes/api.php use App\Http\Controllers\Api\PostController; use App\Http\Controllers\Api\AuthController; // مسارات عامة Route::post('/login', [AuthController::class, 'login']); Route::post('/register', [AuthController::class, 'register']); // مسارات محمية Route::middleware('auth:sanctum')->group(function () { Route::get('/user', function (Request $request) { return $request->user(); }); Route::post('/logout', [AuthController::class, 'logout']); Route::post('/logout-all', [AuthController::class, 'logoutAll']); Route::apiResource('posts', PostController::class); Route::apiResource('comments', CommentController::class); });

إجراء طلبات مصادقة

قم بتضمين الرمز في رأس Authorization عند إجراء طلبات API:

// مثال JavaScript fetch fetch('https://api.example.com/api/user', { headers: { 'Authorization': 'Bearer YOUR_API_TOKEN_HERE', 'Accept': 'application/json', } }) .then(response => response.json()) .then(data => console.log(data)); // مثال Axios axios.get('/api/user', { headers: { 'Authorization': `Bearer ${token}`, } }) .then(response => console.log(response.data)); // مثال PHP cURL $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, 'https://api.example.com/api/user'); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Authorization: Bearer YOUR_API_TOKEN_HERE', 'Accept: application/json', ]); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); curl_close($ch);

مصادقة SPA

لتطبيقات الصفحة الواحدة التي تعمل على نفس النطاق، يستخدم Sanctum ملفات تعريف ارتباط جلسة Laravel:

1. تكوين CORS والجلسة

قم بتحديث config/cors.php:

<?php return [ 'paths' => ['api/*', 'sanctum/csrf-cookie'], 'allowed_methods' => ['*'], 'allowed_origins' => ['http://localhost:3000'], // عنوان URL الخاص بـ SPA 'allowed_origins_patterns' => [], 'allowed_headers' => ['*'], 'exposed_headers' => [], 'max_age' => 0, 'supports_credentials' => true, ];

2. تهيئة حماية CSRF

قبل تسجيل الدخول، احصل على رمز CSRF من نقطة النهاية /sanctum/csrf-cookie:

// في SPA الخاص بك (Vue، React، إلخ.) // الخطوة 1: احصل على ملف تعريف ارتباط CSRF await axios.get('/sanctum/csrf-cookie'); // الخطوة 2: قم بإجراء طلب تسجيل الدخول await axios.post('/login', { email: 'user@example.com', password: 'password' }); // الخطوة 3: قم بإجراء طلبات مصادقة const response = await axios.get('/api/user');

3. تكوين النطاقات ذات الحالة

في config/sanctum.php، حدد النطاقات التي يمكنها إجراء طلبات API ذات حالة:

<?php return [ '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) : '' ) )), 'guard' => ['web'], 'expiration' => null, 'middleware' => [ 'verify_csrf_token' => App\Http\Middleware\VerifyCsrfToken::class, 'encrypt_cookies' => App\Http\Middleware\EncryptCookies::class, ], ];
تحذير: تعمل مصادقة SPA فقط عندما تكون API و SPA على نفس النطاق من المستوى الأعلى. للنطاقات المختلفة، استخدم مصادقة رمز API بدلاً من ذلك.

إدارة الرموز

إدارة رموز المستخدم برمجيًا:

<?php // الحصول على جميع رموز المستخدم $tokens = $user->tokens; // الحصول على الرمز الحالي $currentToken = $request->user()->currentAccessToken(); // التحقق من قدرات الرمز $canCreatePost = $currentToken->can('post:create'); $canDeletePost = $currentToken->can('post:delete'); // إلغاء رمز محدد $user->tokens()->where('id', $tokenId)->delete(); // إلغاء جميع الرموز $user->tokens()->delete(); // انتهاء صلاحية الرمز (يتم تعيينه في config/sanctum.php) 'expiration' => 60, // دقائق // التحقق مما إذا كان الرمز منتهي الصلاحية if ($token->expires_at && now()->greaterThan($token->expires_at)) { // الرمز منتهي الصلاحية }

مصادقة تطبيق الهاتف المحمول

قم بتنفيذ تدفق مصادقة كامل لتطبيقات الهاتف المحمول:

<?php namespace App\Http\Controllers\Api; use App\Http\Controllers\Controller; use App\Models\User; use Illuminate\Http\Request; use Illuminate\Support\Facades\Hash; use Illuminate\Validation\ValidationException; class MobileAuthController extends Controller { public function register(Request $request) { $request->validate([ 'name' => 'required|string|max:255', 'email' => 'required|string|email|max:255|unique:users', 'password' => 'required|string|min:8|confirmed', 'device_name' => 'required|string', ]); $user = User::create([ 'name' => $request->name, 'email' => $request->email, 'password' => Hash::make($request->password), ]); $token = $user->createToken($request->device_name)->plainTextToken; return response()->json([ 'user' => $user, 'token' => $token, ], 201); } public function login(Request $request) { $request->validate([ 'email' => 'required|email', 'password' => 'required', 'device_name' => 'required', ]); $user = User::where('email', $request->email)->first(); if (!$user || !Hash::check($request->password, $user->password)) { throw ValidationException::withMessages([ 'email' => ['بيانات الاعتماد المقدمة غير صحيحة.'], ]); } // اختياريًا، إلغاء الرموز الموجودة لهذا الجهاز $user->tokens()->where('name', $request->device_name)->delete(); $token = $user->createToken($request->device_name)->plainTextToken; return response()->json([ 'user' => $user, 'token' => $token, ]); } public function profile(Request $request) { return response()->json([ 'user' => $request->user(), 'token_name' => $request->user()->currentAccessToken()->name, ]); } public function updateProfile(Request $request) { $request->validate([ 'name' => 'sometimes|string|max:255', 'email' => 'sometimes|email|unique:users,email,' . $request->user()->id, ]); $request->user()->update($request->only(['name', 'email'])); return response()->json([ 'user' => $request->user(), 'message' => 'تم تحديث الملف الشخصي بنجاح', ]); } }

تمرين 1: مصادقة API الأساسية

أنشئ نظام مصادقة API كامل:

  1. قم بتثبيت وتكوين Sanctum
  2. أنشئ نقاط نهاية التسجيل وتسجيل الدخول
  3. أنشئ نقطة نهاية محمية /api/profile
  4. اختبر باستخدام Postman أو cURL
  5. قم بتنفيذ إلغاء الرمز (تسجيل الخروج)

تمرين 2: قدرات الرمز

قم بتنفيذ الأذونات الدقيقة باستخدام قدرات الرمز:

  1. أنشئ رموزًا بقدرات مختلفة (admin، user، read-only)
  2. احمِ المسارات باستخدام middleware ability
  3. أنشئ نقطة نهاية لإدراج رموز المستخدم النشطة
  4. اسمح للمستخدمين بإلغاء رموز فردية
  5. اختبر أن القدرات غير المصرح بها يتم رفضها

تمرين 3: مصادقة SPA

قم بإعداد مصادقة قائمة على الجلسة لـ Vue أو React SPA:

  1. قم بتكوين CORS والنطاقات ذات الحالة
  2. أنشئ نموذج تسجيل دخول يحصل على رمز CSRF أولاً
  3. قم بتنفيذ تسجيل الدخول وتسجيل الخروج وجلب الملف الشخصي
  4. أضف اعتراضات axios للتعامل مع استجابات 401
  5. اختبر أن ملفات تعريف الارتباط يتم تعيينها وإرسالها بشكل صحيح

أفضل الممارسات

  • استخدم أسماء الأجهزة: اطلب دائمًا device_name عند إنشاء الرموز لتتبع أفضل
  • تعيين انتهاء الصلاحية: قم بتكوين انتهاء صلاحية الرمز في config/sanctum.php للأمان
  • إلغاء عند تغيير كلمة المرور: احذف جميع الرموز عندما يغير المستخدمون كلمات المرور
  • استخدم القدرات: قم بتنفيذ قدرات الرمز للتحكم الدقيق في الوصول
  • HTTPS فقط: استخدم HTTPS دائمًا في الإنتاج لحماية الرموز
  • تحديد المعدل: طبق تحديد المعدل على نقاط نهاية المصادقة
  • تسجيل نشاط الرمز: تتبع إنشاء واستخدام الرمز لتدقيق الأمان

الخلاصة

في هذا الدرس، تعلمت:

  • ما هو Laravel Sanctum ومتى تستخدمه
  • كيفية تثبيت وتكوين Sanctum
  • إصدار وإلغاء رموز API
  • تنفيذ قدرات الرمز للأذونات
  • حماية المسارات باستخدام middleware auth:sanctum
  • مصادقة SPA باستخدام ملفات تعريف ارتباط الجلسة
  • بناء مصادقة لتطبيقات الهاتف المحمول
  • أفضل الممارسات لإدارة الرموز الآمنة

توفر Sanctum نظام مصادقة بسيط وآمن مثالي للتطبيقات الحديثة. اختر رموز API لتطبيقات الهاتف المحمول وتكاملات الطرف الثالث، ومصادقة قائمة على الجلسة لـ SPA على نفس النطاق.