Усі три способи ведуть до тієї самої політики - різниця в тому, коли перевірка спрацьовує і які дані їй доступні.
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 публічний метод компонента - теж ендпойнт, який перевіряє права сам.