البرمجيّات الوسيطة (Middleware) في Laravel

من موسوعة حسوب
اذهب إلى: تصفح، ابحث

مقدمة

تُوفِّر البرمجيّات الوسيطة آلية ملائمة لفرز الطلبات HTTP التي تدخل تطبيقك. على سبيل المثال، يحتوي Laravel على برمجيّّة وسيطة تتحقق إن كان مستخدم تطبيقك مصادقا عليه (authenticated). في حالة لم يكن مصادقا عليه، تعيد البرمجيّة الوسيطة توجيهه لصفحة تسجيل الدخول. في حالة كان مصادقا عليه، ستسمح البرمجيّة للطلب بالمرور لسائر التطبيق.

يمكن طبعا كتابة برمجيّات وسيطة للقيام بمهام متنوعة عديدة عدا تسجيل الدخول. قد تكون برمجيّة CORS وسيطة مسؤولة عن إضافة الترويسات (headers) المناسبة لكل الردود التي يرسلها تطبيقك. قد يُسجِّل برنامج تسجيل (logging) كل الطلبات الواردة لتطبيقك.

يحتوي إطار Laravel على عدّة برمجيّات وسيطة، بما فيها برمجيّات استيثاق و حماية CSRF. كل هذه البرمجيّات الوسيطة موجودة في المجلد app/Http/Middleware.

تعريف البرمجيّات الوسيطة

استخدم  أمر make:middleware Artisan  لإنشاء برمجيّة وسيطة:
php artisan make:middleware CheckAge
سيضع هذا الأمر صنف CheckAge جديد بمجلَّد app/Http/Middleware. لن نسمح في هذه البرمجيّة بالوصول للمسار إلا إن كان age المقدّم أكبر من 200. سيُعاد توجيه المستخدمين تجاه URI home في ما عدا ذلك.
<?php

namespace App\Http\Middleware;

use Closure;

class CheckAge
{
    /**
     * عالج الطلب الوارد.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if ($request->age <= 200) {
            return redirect('home');
        }

        return $next($request);
    }
}
كما ترى، تُعيد البرمجيّة إعادة توجيه HTTP للعميل إن قُدِّم سن age أصغر أو مساوي 200. في الحالات المخالفة، يُمرر الطلب للتطبيق. لتمرير الطلب بشكل أعمق عبر التطبيق (بالسماح للبرمجيّة الوسيطة "بالعبور") استدع دالة رد النداء ‎(callback) $next مع request$.

من المستحسن تَخيُّل البرمجيّة الوسيطة كسلسلة من "الطبقات" على الطلبات HTTP يجب المرور عبرها قبل وصولهم لتطبيقك. تستطيع كل طبقة فحص الطلب ورفضه حتى. ملاحظة: تُستبين كل البرمجيّات الوسيطة عبر حاوي الخدمات لذلك تستطيع التلميح على نوع أي اعتماديّات تحتاجها داخل تابع برمجيّتك الوسيطة الباني.

قبل وبعد البرمجيّات الوسيطة

يعتمد تشغيل البرمجيّة الوسيطة قبل أو بعد الطلب على البرمجيّة بحد ذاتها. على سبيل المثال، تقوم  البرمجيّة الوسيطة التالية بالمهمة قبل معالجة التطبيق للطلب:
<?php

namespace App\Http\Middleware;

use Closure;

class BeforeMiddleware
{
    public function handle($request, Closure $next)
    {
       // إجراء الفعل

        return $next($request);
    }
}
بينما هذه البرمجيّة تقوم بالمهمة بعد معالجة التطبيق للطلب:
<?php

namespace App\Http\Middleware;

use Closure;

class AfterMiddleware
{
    public function handle($request, Closure $next)
    {
        $response = $next($request);

       //  إجراء الفعل

        return $response;
    }
}

تسجيل البرمجيّة الوسيطة

البرمجيّة الوسيطة العامة (Global Middleware)

إن رغبت بتشغيل برمجيّة وسيطة مع كل طلب HTTP لتطبيقك، أدرج صنف البرمجيّة الوسيطة في خاصية middleware$ من صنف app/Http/Kernel.php.

تعيين برمجيّات وسيطة على مسارات (Routes)

ان رغبت في تعيين برمجيّات وسيطة على مسارات معينة، عليك أولا أن تعين للبرمجيّة الوسيطة مفتاحا في ملفك app/Http/Kernel.php. تحتوي الخاصية routeMiddleware$ من هذا الصنف على مدخلات للبرمجيّات الوسيطة المحتواة في Laravel. لإضافة برمجيتك، ضعها في هذه القائمة وعين لها مفتاحا من اختيارك. مثلا:
//  App\Http\Kernel داخل الصنف

protected $routeMiddleware = [
    'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
    'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
    'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
    'can' => \Illuminate\Auth\Middleware\Authorize::class,
    'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
    'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
];
بعد تعريف البرمجيّة الوسيطة في النواة ،HTTP تستطيع استخدام التابع middleware لتعيين برمجيّة وسيطة على مسار:
Route::get('admin/profile', function () {
   //
})->middleware('auth');
تستطيع أيضًا تعيين عدة برمجيّات وسيطة للمسار:
Route::get('/', function () {
   //
})->middleware('first', 'second');
تستطيع أيضًا تمرير اسم الصنف المؤهّل كليّا (fully qualified class) عند تعيين البرمجيّات الوسيطة:
use App\Http\Middleware\CheckAge;

Route::get('admin/profile', function () {
   //
})->middleware(CheckAge::class);

مجموعات البرمجيّات الوسيطة

قد ترغب أحيانا في تجميع عدّة برمجيّات وسيطة تحت مفتاح واحد لتسهيل تعيينهم على مسارات. تستطيع فعل هذا باستخدام الخاصية middlewareGroups$ من النواة HTTP.

يأتي Laravel بمجموعتي البرمجيّات الوسيطة api و web مباشرة وتحتويان البرمجيّات الشائعة التي قد ترغب بتطبيقها على web UI والمسارات API:
/**
 * مجموعة برمجيّات التطبيق الوسيطة 
 *
 * @var array
 */
protected $middlewareGroups = [
    'web' => [
        \App\Http\Middleware\EncryptCookies::class,
        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        \Illuminate\Session\Middleware\StartSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \App\Http\Middleware\VerifyCsrfToken::class,
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],

    'api' => [
        'throttle:60,1',
        'auth:api',
    ],
];
يمكن تعيين مجموعات البرمجيّات الوسيطة على المسارات ووحدات التحكّم باستخدام نفس الصيغة (syntax) التي نستخدمها لتعيين برمجيّة وسيطة وحيدة. مرّة أخرى، نجد أن مجموعات البرمجيّات الوسيطة تسهّل تعيين عدّة برمجيّات على المسار في دفعة واحدة:
Route::get('/', function () {
   //
})->middleware('web');

Route::group(['middleware' => ['web']], function () {
   //
});
ملاحظة: تُطبّق مجموعة البرمجيّات الوسيطة web تلقائيًّا على الملف routes/web.php من طرف RouteServiceProvider.

معاملات البرمجيّات الوسيطة (Middleware Parameters)

تستطيع البرمجيّات الوسيطة تلقّي معاملات () إضافيّة. على سبيل المثال، إن احتاج تطبيقك للتحقّق من صلاحيات (role) مستخدم مصادق عليه (authenticated user) قبل تنفيذ فعل ما، تستطيع إنشاء برمجيّة وسيطة CheckRole تتلقّى اسم الصلاحيّة كمتغيّر وسيط.

ستمرّر معاملات برمجيّات وسيطة إضافيّة للبرمجيّة الوسيطة بعد المتغيّر الوسيط next$:
<?php

namespace App\Http\Middleware;

use Closure;

class CheckRole
{
    /**
     *   معالجة الطلب الآتي 
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @param  string  $role
     * @return mixed
     */
    public function handle($request, Closure $next, $role)
    {
        if (! $request->user()->hasRole($role)) {
           // Redirect...
        }

        return $next($request);
    }

}
يمكن تحديد معاملات البرمجيّات الوسيطة (Middleware parameters) عند تعريف المسار بفصل اسم البرمجيّة الوسيطة و المعاملة بعلامة : .إن وجدت أكثر من معاملة يجب الفصل بينهن بفواصل:
Route::put('post/{id}', function ($id) {
   //
})->middleware('role:editor');

البرمجيّات القابلة للإنهاء (Terminable Middleware)

قد تحتاج البرمجيّات الوسيطة أحيانا للقيام ببعض الأعمال بعد تجهيز الرد HTTP. على سبيل المثال، تكتب البرمجيّة "session" الوسيطة المحتواة في Laravel بيانات الجلسة للتخزين بعد تجهيز الردّ كليّا. إن عرّفت تابع terminate ببرمجيّتك الوسيطة ستُستَدعى مباشرة بعد جهوزيّة ردّك للإرسال للمُتصفّح.
<?php

namespace Illuminate\Session\Middleware;

use Closure;

class StartSession
{
    public function handle($request, Closure $next)
    {
        return $next($request);
    }

    public function terminate($request, $response)
    {
       //  تخزين بيانات الجلسة...
    }
}

يجب على التابع terminate أن يتلقّى كلا من الطلب والردّ. يجب إضافة البرمجيّة الوسيطة فور تعريفها لقائمة المسارات أو البرمجيّات الوسيطة العامّة في الملف app/Http/Kernel.php.

سيستبين Laravel نسخة جديدة من البرمجيّة الوسيطة من حاوي الخدمات عند مناداة التابع terminate على برمجيّتك الوسيطة. إن رغبت باستخدام نفس نسخة البرمجيّة الوسيطة عند استدعاء التابعين handle و terminate، سجّل البرمجيّة الوسيطة في الحاوي باستخدام دالة الحاوي singleton.

مصادر