Некоторые middleware должны выполняться в определенной точке стандартного стека Laravel. Middleware, которое считывает IP-адрес клиента, должно выполняться после TrustProxies . Middleware, считывающее сессию, должно выполняться после StartSession , а middleware, изменяющее разрешение моделей маршрутов — перед SubstituteBindings .
Колбэк withMiddleware() в bootstrap/app.php позволял добавлять middleware в начало или конец глобального стека и группы, но не рядом с конкретным встроенным middleware. В Laravel 13.40 добавлены четыре метода для этих целей, а также появилась возможность передавать массив в существующие методы replace() .
#Вставка рядом со встроенным middleware
Методы insertBefore() и insertAfter() работают с глобальным стеком middleware. Первый аргумент — это middleware, которое нужно найти, а второй — одно middleware или массив таковых:
use App\Http\Middleware\BlockBannedIps; use App\Http\Middleware\SanitizeInput; use Illuminate\Foundation\Http\Middleware\TrimStrings; use Illuminate\Http\Middleware\TrustProxies; ->withMiddleware(function (Middleware $middleware) { $middleware->insertAfter(TrustProxies::class, BlockBannedIps::class); $middleware->insertBefore(TrimStrings::class, SanitizeInput::class); })
Методы insertBeforeInGroup() и insertAfterInGroup() делают то же самое внутри группы middleware. Первым аргументом они принимают имя группы:
use App\Http\Middleware\SetLocaleFromSession; use Illuminate\Session\Middleware\StartSession; ->withMiddleware(function (Middleware $middleware) { $middleware->insertAfterInGroup('web', StartSession::class, SetLocaleFromSession::class); })
Эти методы работают с любыми группами, включая те, которые вы определяете с помощью $middleware->group() .
#Замена с помощью массива
Новые методы основаны на небольшом изменении от того же автора. Теперь методы replace() и replaceInGroup() принимают массив, который заменяет исходное middleware в стеке. Чтобы выполнить вставку рядом с определенным middleware, включите его в массив:
// Run StripCrossOriginReferer after TrustProxies $middleware->replace(TrustProxies::class, [ TrustProxies::class, StripCrossOriginReferer::class, ]); // Replace one middleware with two $middleware->replace(Foo::class, [Bar::class, Baz::class]);
Хелперы web() и api() передают свой аргумент replace в replaceInGroup() , поэтому массивы работают и там:
$middleware->web(replace: [ StartSession::class => [StartSession::class, SetLocaleFromSession::class], ]);
#Пример: локаль из сессии
Некоторые приложения сохраняют язык пользователя в сессии и переводят URL-слаги. Маршрут /fr/articles/{article} может разрешать статью по ее французскому слагу с помощью модели, которая считывает текущую локаль в resolveRouteBinding() :
class Article extends Model { public function resolveRouteBinding($value, $field = null) { return $this->where('slug->'.app()->getLocale(), $value)->firstOrFail(); } }
Локаль должна устанавливаться после запуска сессии и до того, как SubstituteBindings разрешит модель. Стандартная группа web выполняется в следующем порядке:
-
EncryptCookies -
AddQueuedCookiesToResponse -
StartSession -
ShareErrorsFromSession -
PreventRequestForgery -
SubstituteBindings
До версии 13.40 ни один хелпер не помещал middleware в нужное место. С web(append: ...) middleware выполняется после SubstituteBindings , поэтому поиск модели происходит с локалью по умолчанию, и французский слаг возвращает 404. С web(prepend: ...) оно выполняется перед StartSession , и $request->session() выбрасывает Session store not set on request.
Временным решением было переопределение всей группы целиком:
$middleware->group('web', [ EncryptCookies::class, AddQueuedCookiesToResponse::class, StartSession::class, SetLocaleFromSession::class, ShareErrorsFromSession::class, PreventRequestForgery::class, SubstituteBindings::class, ]);
Такая копия не учитывает изменения в фреймворке. В Laravel 12 в этой группе использовался ValidateCsrfToken , а в Laravel 13 используется PreventRequestForgery , поэтому приложение, скопировавшее группу из Laravel 12, сохранило бы старый класс после обновления. Скопированный список также теряет auth.session , который Laravel добавляет в группу при вызове $middleware->authenticateSessions() .
Начиная с версии 13.40, вам достаточно указать только добавляемое middleware:
->withMiddleware(function (Middleware $middleware) { $middleware->insertAfterInGroup('web', StartSession::class, SetLocaleFromSession::class); })
Это middleware считывает сессию и устанавливает локаль:
class SetLocaleFromSession { public function handle(Request $request, Closure $next): Response { if ($locale = $request->session()->get('locale')) { App::setLocale($locale); } return $next($request); } }
В результате получается следующая группа: EncryptCookies , AddQueuedCookiesToResponse , StartSession , SetLocaleFromSession , ShareErrorsFromSession , PreventRequestForgery , SubstituteBindings .
#Пример: IP-адрес клиента
Глобальный стек имеет ту же проблему. Middleware, проверяющее $request->ip() по списку заблокированных адресов, получит адрес балансировщика нагрузки, если оно выполняется перед TrustProxies , а prepend() помещает его перед TrustProxies . С помощью append() оно запускается после HandleCors , проверки режима обслуживания и middleware для входных данных.
Вместо этого выполните вставку сразу после TrustProxies :
$middleware->insertAfter(TrustProxies::class, BlockBannedIps::class);
class BlockBannedIps { public function handle(Request $request, Closure $next): Response { if (in_array($request->ip(), config('security.banned_ips'), true)) { abort(403); } return $next($request); } }
#Дополнительное чтение
- Slow Job Alerts and Replica Commit IDs in Laravel 13.40
- How to Configure Middleware in Laravel
- Managing Proxy Trust in Laravel Applications
Джейми Йорк (Jamie York) добавил поддержку массивов для replace() в пулреквесте #62230 и методы вставки в #62261.
Комментарии (0)
Пока нет комментариев — будьте первым.