Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Middle: питання на співбесіді з теми «Авторизація»

Питання з реальних співбесід з відповідями: Laravel і PHP, бази даних, JavaScript і фронтенд, Git, Docker, API, безпека й архітектура. Тими самими темами, що й тести.

4 питання

  • Gate - замикання для простих, не прив'язаних до моделі перевірок.
  • Policy - клас, що групує правила авторизації навколо конкретної моделі.
// Gate
Gate::define('view-admin', fn (User $u) => $u->is_admin);

// Policy
class PostPolicy
{
    public function update(User $user, Post $post): bool
    {
        return $user->id === $post->user_id;
    }
}

Застосування:

$this->authorize('update', $post); // у контролері
@can('update', $post) ... @endcan // у Blade
$user->can('update', $post); // будь-де

Політики автоматично відкривають 403 при відмові.

Докладніше в документації: Авторизація (Gates та Policies)

bool каже лише «можна» чи «ні». Response дає ще й пояснення та керує тим, що побачить користувач.

Повідомлення про причину:

public function update(User $user, Post $post): Response
{
    if ($post->is_locked) {
        return Response::deny('Статтю заблоковано модератором.');
    }

    return $user->id === $post->user_id
        ? Response::allow()
        : Response::deny('Ви не автор цієї статті.');
}

Коли Gate::authorize('update', $post) кидає AuthorizationException, це повідомлення потрапляє у відповідь 403. Без винятку його можна прочитати через Gate::inspect() - наприклад, щоб показати підказку біля неактивної кнопки.

404 замість 403:

return $user->id === $invoice->user_id
    ? Response::allow()
    : Response::denyAsNotFound();

403 підтверджує, що рахунок з таким номером існує. Для приватних ресурсів 404 нічого не розкриває - стороння людина не відрізнить чужий рахунок від неіснуючого. Є й denyWithStatus() для довільного коду.

Коли досить bool: коли причина очевидна й однакова - «не власник». Response окупається, де причин кілька або сам факт існування ресурсу приватний.

Докладніше в документації: Відповіді політик

Усі три способи ведуть до тієї самої політики - різниця в тому, коли перевірка спрацьовує і які дані їй доступні.

Middleware can - найраніше, ще до контролера:

Route::put('/posts/{post}', [PostController::class, 'update'])
    ->middleware('can:update,post');

Модель береться з прив'язки маршруту. Добре, коли рішення залежить лише від користувача й моделі з URL.

Form Request authorize() - перед валідацією:

public function authorize(): bool
{
    return $this->user()->can('update', $this->route('post'));
}

Зручно, коли запит і так має Form Request: права й правила даних в одному класі.

У контролері Gate::authorize() - коли рішення залежить від чогось, що з'являється лише в коді: від даних запиту чи від іншої моделі.

Gate::authorize('transfer', [$account, $request->integer('amount')]);

У Laravel 11+ базовий контролер порожній, тож $this->authorize() доступний лише з трейтом AuthorizesRequests.

Що важливо незалежно від способу: перевірка має бути на сервері для кожної дії. Схована кнопка в Blade чи Livewire не захищає - запит можна відправити напряму. І в Livewire публічний метод компонента - теж ендпойнт, який перевіряє права сам.

Докладніше в документації: Авторизація дій через політики

Через перевірку, що виконується перед усіма іншими.

Для всього застосунку - Gate::before():

// AppServiceProvider::boot()
Gate::before(function (User $user, string $ability) {
    return $user->isSuperAdmin() ? true : null;
});

Для однієї політики - метод before():

public function before(User $user, string $ability): ?bool
{
    return $user->isSuperAdmin() ? true : null;
}

Головне - повертати null, а не false, для всіх, хто не суперадмін. null означає «не вирішую, перевіряй далі», а false заборонив би дію всім іншим, не дійшовши до політики.

Gate::after() - навпаки, спрацьовує після перевірок і впливає на результат, лише якщо гейт чи політика повернули null. Зручно для правила за замовчуванням.

Обережно з «усім можна»:

  • суперадмін через before обійде навіть правила, які мали б діяти для всіх, - наприклад, «не можна видалити оплачене замовлення»; такі бізнес-обмеження краще перевіряти окремо від прав;
  • дії суперадміна варто журналювати;
  • для гнучкої моделі ролей і прав зазвичай беруть пакет на кшталт spatie/laravel-permission, а before лишають для однієї надролі.

Докладніше в документації: Фільтри політик