---
title: "Порядок авторизації та прив’язки моделей у Laravel: чому замість 403 приходить 404"
url: https://laravelukraine.com/blog/poriadok-avtorizaciyi-ta-priviazki-modelei-u-laravel-comu-zamist-403-prixodit-404
date: 2026-10-07
source: https://masteringlaravel.io/daily/2026-10-07-republished-understanding-the-order-of-authorization-and-model-binding
---

# Порядок авторизації та прив’язки моделей у Laravel: чому замість 403 приходить 404

Команда Mastering Laravel [дуже любить пакет laravel-permission](https://masteringlaravel.io/daily/2024-02-19-simple-rules-for-writing-authorization-logic) і використовує його на більшості проєктів. Автор матеріалу Joel розповідає про неочевидну поведінку, яка виникає, коли авторизація на основі прав поєднується з прив’язкою моделей до маршрутів.

## Перевірка прав через middleware `can`

Зручна особливість пакета в тому, що він дозволяє використовувати штатний middleware Laravel `can`, щоб перевірити, чи має користувач певний дозвіл. У файлі маршрутів можна обгорнути цілу групу маршрутів у перевірку на основі права:

```php
// routes/web.php

Route::middleware('can:manage-articles')->group(function () {
    Route::get('/articles', 'ArticleController@index');
    Route::get('/articles/{article}', 'ArticleController@show');
    // more article routes...
});
```

У реальних проєктах замість рядка зазвичай використовують enum `Permission`, але в прикладі для простоти та читабельності вжито рядок.

Якщо в користувача немає права `manage-articles`, він не повинен мати доступу до жодного з цих маршрутів. Додаткові, більш деталізовані перевірки на кшталт «чи може він редагувати саме цю модель Article» тут не потрібні - доступ просто відхиляється на ранньому етапі.

## Несподівана поведінка: 404 замість 403

Проте трапляється неочікуване. Якщо користувач без права доступу до цієї групи звертається до маршруту на кшталт `/articles/123`, де `123` - неіснуюча стаття, він отримає помилку 404, а не очікувану 403. Причина - route model binding.

За замовчуванням Laravel надає middleware `SubstituteBindings` вищий пріоритет, ніж middleware `Authorize`. Тому, якщо модель не знайдено, відповідь 404 повертається ще до того, як `Authorize` матиме змогу віддати 403.

## Чому порядок саме такий

Перш ніж шукати рішення, варто зрозуміти, навіщо так зроблено. Деякі методи класичних політик (policies) потребують уже прив’язаної моделі. Наприклад, типовий метод `edit` у політиці виглядає так:

```php
public function edit(User $user, Article $article)
{
    return $user->id === $article->user_id;
}
```

Якщо модель не прив’язана, метод політики не можна виконати, а отже middleware `Authorize` не зможе виконати свою роботу. Тому логічно, що `SubstituteBindings` спрацьовує першим.

У розглянутому прикладі прив’язана модель не потрібна, але проста зміна порядку middleware місцями зламає ту частину логіки авторизації в політиках, яка залежить від прив’язаної моделі.

## Рішення

У такому випадку можна скористатися [middleware самого пакета](https://spatie.be/docs/laravel-permission/v5/basic-usage/middleware#content-package-middleware) - `PermissionMiddleware` - замість `can`, а також [переконатися, що він має вищий пріоритет](https://laravel.com/docs/11.x/middleware#sorting-middleware), ніж `SubstituteBindings`. Так перевірка прав виконається раніше за прив’язку моделей, а політики, що потребують моделі, продовжать працювати як раніше.
