آموزش لاراول 7: آموزش Middleware در لاراول

مقدمه

در این بخش از سری آموزش مقالات لاراول، میخواهیم به آموزش میان افزار یا Middleware بپردازیم. Middleware سازوکاری مناسب برای فیلتر کردن درخواستهای HTTP که به برنامه شما وارد می شود ، ارائه می دهد. به عنوان مثال ، لاراول شامل یک middleware است که احراز هویت کاربر برنامه شما را تأیید می کند. اگر کاربر احراز هویت نشود ، middleware کاربر را به صفحه login هدایت می کند. با این وجود ، در صورت احراز هویت کاربر ، middleware به شما اجازه می دهد تا درخواست در ادامه برنامه وارد شود.

Middleware های بیشتری را می توان برای انجام کارهای مختلف علاوه بر احراز هویت نوشت. یک CORS middleware می تواند مسئول اضافه کردن هدرهای مناسب به تمام response هایی باشد که از برنامه شما خارج می شود. یک logging middleware می تواند تمام درخواست های ورودی به برنامه شما را لاگ کند.

چندین middleware در فریم ورک لاراول وجود دارد ، از جمله authentication و CSRF protection. همه این middleware ها در دایرکتوری app/Http/Middleware قرار دارند.

تعریف Middleware

برای تعریف یک middleware جدید ، از دستور make:middleware Artisan استفاده کنید:

php artisan make:middleware CheckAge

این دستور یک کلاس CheckAge جدید در دایرکتوری app/Http/Middleware شما قرار می دهد. در این middleware ، ما فقط در صورتی مجاز به دسترسی به route هستیم که age بزرگتر از 200 باشد. در غیر این صورت ، ما کاربران را به home URI هدایت می کنیم:

‌<‌?php

    namespace App\Http\Middleware;

    use Closure;

    class CheckAge
    {
        /**
         * Handle an incoming request.
         *
         * @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);
        }
    }

همانطور که مشاهده می کنید ، اگر age مشخص شده کمتر یا برابر 200 باشد ، middleware هدایت HTTP را به مشتری باز می گرداند. در غیر این صورت ، درخواست بیشتر به برنامه ارسال می شود. برای ارسال بیشتر درخواست به برنامه، $next callback با $request را فراخوانی کنید.

قبل و بعد از Middleware

اینکه یک middleware قبل از request اجرا شود یا بعد از آن ، به خود middleware بستگی دارد. به عنوان مثال ، middleware زیر قبل از رسیدگی به درخواست توسط برنامه ، برخی تسک ها را انجام می دهد:

‌<‌?php

    namespace App\Http\Middleware;

    use Closure;

    class BeforeMiddleware
    {
        public function handle($request, Closure $next)
        {
            // Perform action

            return $next($request);
        }
    }

این middleware پس از درخواست توسط برنامه ، وظیفه خود را انجام می دهد:

‌<‌?php

    namespace App\Http\Middleware;

    use Closure;

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

            // Perform action

            return $response;
        }
    }

Registering Middleware

Global Middleware

اگر می خواهید middleware در هنگام HTTP request به برنامه اجرا شود ، کلاس middleware را در ویژگی $middleware کلاس app/Http/Kernel.php قرار دهید.

اختصاص Route به Middleware

اگر می خواهید middleware را به route های خاصی assign کنید ، ابتدا باید middleware key را در فایل app/Http/Kernel.php تخصیص دهید. به طور پیش فرض ، ویژگی $routeMiddleware این کلاس شامل ورودی هایی برای middleware موجود در Laravel است. برای افزودن مورد خود ، آن را به این لیست اضافه کنید و یک key دلخواه به آن اختصاص دهید:

// Within App\Http\Kernel Class...

    protected $routeMiddleware = [
        'auth' =‌>‌ \App\Http\Middleware\Authenticate::class,
        'auth.basic' =‌>‌ \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
        'bindings' =‌>‌ \Illuminate\Routing\Middleware\SubstituteBindings::class,
        'cache.headers' =‌>‌ \Illuminate\Http\Middleware\SetCacheHeaders::class,
        'can' =‌>‌ \Illuminate\Auth\Middleware\Authorize::class,
        'guest' =‌>‌ \App\Http\Middleware\RedirectIfAuthenticated::class,
        'signed' =‌>‌ \Illuminate\Routing\Middleware\ValidateSignature::class,
        'throttle' =‌>‌ \Illuminate\Routing\Middleware\ThrottleRequests::class,
        'verified' =‌>‌ \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
    ];

هنگامی که middleware در HTTP kernel تعریف شد ، می توانید از متد middleware برای اختصاص middleware به یک route استفاده کنید:

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

همچنین می توانید چندین middleware به route اختصاص دهید:

Route::get('/', function () {
        //
    })-‌>‌middleware('first', 'second');

هنگام اختصاص middleware ، می توانید نام class را نیز ارسال کنید:

use App\Http\Middleware\CheckAge;

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

هنگام اختصاص middleware به گروهی از route ها ، ممکن است لازم باشد گاهی اوقات از اعمال middleware در یک routeجداگانه در گروه جلوگیری کنید. این کار را می توانید با استفاده از متد withoutMiddleware انجام دهید:

use App\Http\Middleware\CheckAge;

    Route::middleware([CheckAge::class])-‌>‌group(function () {
        Route::get('/', function () {
            //
        });

        Route::get('admin/profile', function () {
            //
        })-‌>‌withoutMiddleware([CheckAge::class]);
    });

متد withoutMiddleware فقط می تواند route middleware را حذف کند و برای global middleware.اعمال نمی شود.

Middleware Groups

بعضی اوقات ممکن است بخواهید چندین middleware را تحت یک key قرار دهید تا انتساب آنها به route ها راحت تر شود. شما می توانید این کار را با استفاده از $middlewareGroups کرنل HTTP انجام دهید.

Laravel با گروه های میان افزار web و api همراه است که شامل middleware مشترکی هستند که ممکن است بخواهید درAPI route و web UI خود اعمال کنید:

/**
     * The application's route middleware groups.
     *
     * @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',
        ],
    ];

Middleware group ها میتوانند به route ها و controller action ها با استفاده از syntax مشابه اختصاص داده شوند.middleware group ها تخصیص همزمان تعدادی middleware به یک route را راحت تر می کنند:

Route::get('/', function () {
        //
    })-‌>‌middleware('web');

    Route::group(['middleware' =‌>‌ ['web']], function () {
        //
    });

    Route::middleware(['web', 'subscribed'])-‌>‌group(function () {
        //
    });

{نکته} web middleware group توسط RouteServiceProvider به طور خودکار بر روی فایلهای routes/web.php اعمال می شود.

Sorting Middleware

به ندرت ، ممکن است شما نیاز داشته باشید تا middleware خود به ترتیب خاصی اجرا شود اما وقتی به route اختصاص می یابند ، ترتیب آنها را کنترل نکنید. در این حالت ، می توانید اولویت middeware را با استفاده از $middlewarePriority فایل app/Http/Kernel.php تعیین کنید:

/**
     * The priority-sorted list of middleware.
     *
     * This forces non-global middleware to always be in the given order.
     *
     * @var array
     */
    protected $middlewarePriority = [
        \Illuminate\Session\Middleware\StartSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \Illuminate\Contracts\Auth\Middleware\AuthenticatesRequests::class,
        \Illuminate\Routing\Middleware\ThrottleRequests::class,
        \Illuminate\Session\Middleware\AuthenticateSession::class,
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
        \Illuminate\Auth\Middleware\Authorize::class,
    ];

پارامترهای Middleware 

Middleware همچنین می تواند پارامترهای اضافی را دریافت کند. به عنوان مثال ، اگر برنامه شما نیاز به تأیید اینکه کاربر معتبر قبل از انجام یک عمل مشخص "role" مشخصی دارد ، می توانید یک CheckRole middleware ایجاد کنید که نام role را به عنوان یک آرگومان اضافی دریافت می کند.

پارامترهای Additional middleware پس از آرگومان$next به middleware ارسال می شوند:

‌<‌?php

    namespace App\Http\Middleware;

    use Closure;

    class CheckRole
    {
        /**
         * Handle the incoming request.
         *
         * @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 می توانند هنگام تعیین route با جدا کردن نام و پارامترهای middleware با یک : مشخص شوند. چندین پارامتر باید با کاما مشخص شوند:

Route::put('post/{id}', function ($id) {
        //
    })-‌>‌middleware('role:editor');

Terminable Middleware

گاهی اوقات ممکن است یک middleware پس از ارسال پاسخ HTTP به مرورگر ، نیاز به انجام برخی کارها داشته باشد. اگر متد terminate را در middleware تعریف کنید و وب سرور شما از FastCGI استفاده کند ، متد terminate پس از ارسال پاسخ به مرورگر ، به طور خودکار فراخوانی می شود:

‌<‌?php

    namespace Illuminate\Session\Middleware;

    use Closure;

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

        public function terminate($request, $response)
        {
            // Store the session data...
        }
    }

متد terminate باید هر دو request و response را دریافت کند. هنگامی که یک terminable middleware تعریف کردید ، باید آن را به لیست route یا global middleware در فایل app/Http/Kernel.php اضافه کنید.

هنگام فراخوانی متد terminate در middlware ، لاراول نمونه جدیدی از middleware را از service container میگیرد. اگر می خواهید هنگام فراخوانی متد های handle و terminate از middleware instance استفاده کنید ، با استفاده از متد container's singleton، میان افزار را با همان container رجیسترکنید. به طور معمول این کار باید در متد register با  AppServiceProvider.php انجام شود:

use App\Http\Middleware\TerminableMiddleware;

    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        $this-‌>‌app-‌>‌singleton(TerminableMiddleware::class);
    }

× در حال پاسخ به: