Любите загадки? Событие еще доступно на сайте.
Ищете работу? Мы поможем!
Ищете работу? Мы поможем!

Посредники

Вы просматриваете документ для прошлой версии.
Рассмотрите возможность обновления вашего проекта до актуальной версии 10.x. Почему это важно?

Введение

Посредники предоставляют удобный механизм для фильтрации HTTP-запросов вашего приложения. Например, в Laravel есть посредник для проверки аутентификации пользователя. Если пользователь не аутентифицирован, посредник перенаправит его на страницу входа в систему. Если же пользователь аутентифицирован, посредник позволит запросу пройти далее в приложение.

Конечно, посредники нужны не только для авторизации. CORS-посредник может пригодиться для добавления особых заголовков ко всем ответам в вашем приложении. А посредник логов может зарегистрировать все входящие запросы.

В Laravel есть несколько стандартных посредников, включая посредники для аутентификации и CSRF-защиты. Все они расположены в директории app/Http/Middleware.

Создание посредника

Чтобы создать посредника, используйте команду Artisan make:middleware:

php artisan make:middleware CheckAge

Эта команда поместит новый класс CheckAge в вашу директорию app/Http/Middleware. В этом посреднике мы будем пропускать только те запросы, в которых age будет больше 200, а во всех остальных случаях будем перенаправлять пользователей на home URI.

<?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);
    }

}

Как видите, если переданный age меньше или равен 200, то посредник вернёт клиенту переадресацию, иначе, запрос будет передан далее в приложение. Чтобы передать запрос дальше в приложение (позволяя посреднику “передать” его), просто вызовите функцию $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;
    }
}

Регистрация посредника

Глобальный посредник

Если вы хотите, чтобы посредник запускался для каждого HTTP-запроса в вашем приложении, добавьте этот посредник в свойство $middleware вашего класса app/Http/Kernel.php.

Назначение посредника роутам

Если вы хотите назначить посредника для конкретных маршрутов, то сначала вам надо добавить ключ посредника в файл 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');

При назначении посредника вы можете указать полное имя класса:

use App\Http\Middleware\CheckAge;

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

Группы посредников

Иногда бывает полезно объединить несколько посредников под одним ключом, чтобы проще назначать их на маршруты. Это можно сделать при помощи свойства $middlewareGroups вашего HTTP-ядра.

Изначально в Laravel есть группы посредников web и api, которые содержат те посредники, которые часто применяются к вашим роутам веб-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',
    ],
];

Группы посредников могут быть назначены роутам и действия контроллера с помощью того же синтаксиса, что и для одного посредника. Группы посредников просто делают проще единое назначение нескольких посредников на роут:

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

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

Изначально группа посредников web автоматически применяется к вашему файлу routes/web.php сервис-провайдером RouteServiceProvider.

Параметры посредника

В посредник можно передавать дополнительные параметры. Например, если в вашем приложении необходима проверка того, есть ли у аутентифицированного пользователя определённая “роль” для выполнения данного действия, вы можете создать посредника 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);
    }

}

Параметры посредника можно указать при определении маршрута, отделив название посредника от параметров двоеточием :. Несколько параметров разделяются запятыми:

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

Посредник terminable

Иногда посредник должен выполнить некоторые действия уже после отправки 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)
    {
        // Store the session data...
    }
}

Метод terminate должен получать и запрос и ответ. Определив terminable-посредника, вы должны добавить его в список посредников роута или глобальных посредников в файл app/Http/Kernel.php.

При вызове метода terminate в посреднике, Laravel получит свежий экземпляр посредника из сервис-контейнера. Если вы хотите использовать тот же самый экземпляр посредника при вызовах методов handle и terminate, зарегистрируйте посредника в контейнере при помощи метода singleton.