1. Основы
  2. Промежуточное программное обеспечение

Введение

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

Дополнительные промежуточные программные обеспечения могут быть написаны для выполнения различных задач помимо аутентификации. Например, промежуточное программное обеспечение регистрации может регистрировать все входящие запросы в вашем приложении. В Laravel включено несколько промежуточных программных обеспечений, включая промежуточные программные обеспечения для аутентификации и защиты от CSRF. Все эти промежуточные программные обеспечения находятся в каталоге app/Http/Middleware.

Определение промежуточного программного обеспечения

Для создания нового промежуточного программного обеспечения используйте команду Artisan make:middleware:

php artisan make:middleware EnsureTokenIsValid

Эта команда поместит новый класс EnsureTokenIsValid в каталог app/Http/Middleware. В этом промежуточном программном обеспечении мы разрешим доступ к маршруту только в том случае, если предоставленный ввод token совпадает с определенным значением. В противном случае мы перенаправим пользователей обратно на URI home:

<?php
 
namespace App\Http\Middleware;
 
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
 
class EnsureTokenIsValid
{
/**
* Обработать входящий запрос.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
if ($request->input('token') !== 'my-secret-token') {
return redirect('home');
}
 
return $next($request);
}
}

Как видите, если предоставленный token не соответствует нашему секретному токену, промежуточное программное обеспечение вернет HTTP-перенаправление клиенту; в противном случае запрос будет передан дальше в приложение. Чтобы передать запрос глубже в приложение (разрешив промежуточному программному обеспечению "пропустить"), вы должны вызвать обратный вызов $next с $request.

Лучше всего представлять промежуточное программное обеспечение как серию "слоев", через которые HTTP-запросы должны проходить, прежде чем они достигнут вашего приложения. Каждый слой может проверять запрос и даже отклонять его полностью.

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

Промежуточное программное обеспечение и ответы

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

<?php
 
namespace App\Http\Middleware;
 
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
 
class BeforeMiddleware
{
public function handle(Request $request, Closure $next): Response
{
// Выполнить действие
 
return $next($request);
}
}

Однако это промежуточное программное обеспечение выполнит свою задачу после обработки запроса приложением:

<?php
 
namespace App\Http\Middleware;
 
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
 
class AfterMiddleware
{
public function handle(Request $request, Closure $next): Response
{
$response = $next($request);
 
// Выполнить действие
 
return $response;
}
}

Регистрация промежуточного программного обеспечения

Глобальное промежуточное программное обеспечение

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

Назначение промежуточного программного обеспечения маршрутам

Если вы хотите назначить промежуточное программное обеспечение для конкретных маршрутов, вы можете вызвать метод middleware при определении маршрута:

use App\Http\Middleware\Authenticate;
 
Route::get('/profile', function () {
// ...
})->middleware(Authenticate::class);

Вы можете назначить несколько промежуточных программных обеспечений для маршрута, передав массив имен промежуточных программных обеспечений методу middleware:

Route::get('/', function () {
// ...
})->middleware([First::class, Second::class]);

Для удобства вы можете назначить псевдонимы промежуточного программного обеспечения в файле вашего приложения app/Http/Kernel.php. По умолчанию в свойстве $middlewareAliases этого класса содержатся записи для промежуточного программного обеспечения, включенного в Laravel. Вы можете добавить свое промежуточное программное обеспечение в этот список и назначить ему псевдоним на ваш выбор:

// Within App\Http\Kernel class...
 
protected $middlewareAliases = [
'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,
];

После того как псевдоним промежуточного программного обеспечения был определен в HTTP-ядре, вы можете использовать псевдоним при назначении промежуточного программного обеспечения маршрутам:

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

Исключение промежуточного программного обеспечения

При назначении промежуточного программного обеспечения группе маршрутов вам иногда может потребоваться предотвратить применение промежуточного программного обеспечения к отдельному маршруту внутри группы. Вы можете сделать это, используя метод withoutMiddleware:

use App\Http\Middleware\EnsureTokenIsValid;
 
Route::middleware([EnsureTokenIsValid::class])->group(function () {
Route::get('/', function () {
// ...
});
 
Route::get('/profile', function () {
// ...
})->withoutMiddleware([EnsureTokenIsValid::class]);
});

Вы также можете исключить определенный набор промежуточного программного обеспечения из целой группы определений маршрутов:

use App\Http\Middleware\EnsureTokenIsValid;
 
Route::withoutMiddleware([EnsureTokenIsValid::class])->group(function () {
Route::get('/profile', function () {
// ...
});
});

Метод withoutMiddleware может только удалять маршрутное промежуточное программное обеспечение и не применяется к глобальному промежуточному программному обеспечению.

Группы промежуточного программного обеспечения

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

Laravel включает предопределенные группы промежуточного программного обеспечения web и api, которые содержат общие промежуточные программные обеспечения, которые вы можете применить к вашим маршрутам веб-интерфейса и API. Помните, эти группы промежуточного программного обеспечения автоматически применяются поставщиком услуг App\Providers\RouteServiceProvider вашего приложения к маршрутам ваших соответствующих файлов маршрутов web и 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' => [
\Illuminate\Routing\Middleware\ThrottleRequests::class.':api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
];

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

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

Примечание По умолчанию группы промежуточного программного обеспечения web и api автоматически применяются к соответствующим файлам routes/web.php и routes/api.php вашего приложения через App\Providers\RouteServiceProvider.

Сортировка промежуточного программного обеспечения

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

/**
* Список промежуточного программного обеспечения, отсортированный по приоритету.
*
* Это заставляет промежуточное программное обеспечение, не являющееся глобальным, всегда следовать заданному порядку.
*
* @var string[]
*/
protected $middlewarePriority = [
\Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests::class,
\Illuminate\Cookie\Middleware\EncryptCookies::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\Illuminate\Contracts\Auth\Middleware\AuthenticatesRequests::class,
\Illuminate\Routing\Middleware\ThrottleRequests::class,
\Illuminate\Routing\Middleware\ThrottleRequestsWithRedis::class,
\Illuminate\Contracts\Session\Middleware\AuthenticatesSessions::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\Illuminate\Auth\Middleware\Authorize::class,
];

Параметры промежуточного программного обеспечения

Промежуточное программное обеспечение также может принимать дополнительные параметры. Например, если ваше приложение должно проверить, что аутентифицированный пользователь имеет определенную "роль" перед выполнением определенного действия, вы можете создать промежуточное программное обеспечение EnsureUserHasRole, которое получает имя роли в качестве дополнительного аргумента.

Дополнительные параметры промежуточного программного обеспечения будут переданы промежуточному программному обеспечению после аргумента $next:

<?php
 
namespace App\Http\Middleware;
 
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
 
class EnsureUserHasRole
{
/**
* Обработать входящий запрос.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next, string $role): Response
{
if (! $request->user()->hasRole($role)) {
// Перенаправление...
}
 
return $next($request);
}
 
}

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

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

Завершающее промежуточное программное обеспечение

Иногда промежуточному программному обеспечению может потребоваться выполнить некоторую работу после отправки HTTP-ответа в браузер. Если вы определите метод terminate в вашем промежуточном программном обеспечении, и ваш веб-сервер использует FastCGI, метод terminate будет автоматически вызван после отправки ответа в браузер:

<?php
 
namespace Illuminate\Session\Middleware;
 
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
 
class TerminatingMiddleware
{
/**
* Обработать входящий запрос.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
return $next($request);
}
 
/**
* Обработать задачи после отправки ответа браузеру.
*/
public function terminate(Request $request, Response $response): void
{
// ...
}
}

Метод terminate должен получать как запрос, так и ответ. После того как вы определили промежуточное программное обеспечение с возможностью завершения, вы должны добавить его в список маршрутов или глобального промежуточного программного обеспечения в файле app/Http/Kernel.php.

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

use App\Http\Middleware\TerminatingMiddleware;
 
/**
* Зарегистрировать любые службы приложения.
*/
public function register(): void
{
$this->app->singleton(TerminatingMiddleware::class);
}