Права доступа
Аутентификация отвечает на вопрос «кто это?», авторизация — «что ему можно?». Вошедший пользователь не должен редактировать чужие статьи. Laravel предлагает для таких правил два инструмента: простые Gate и классы Policy.
Gate
Gate — правило с именем. Его объявляют в методе boot() класса AppServiceProvider:
use App\Models\User;
use Illuminate\Support\Facades\Gate;
public function boot(): void
{
Gate::define('access-admin', function (User $user) {
return $user->is_admin;
});
}Проверка в коде:
if (Gate::allows('access-admin')) {
// показать панель администратора
}
Gate::authorize('access-admin'); // при отказе — ошибка 403Gate подходит для правил, не привязанных к конкретной модели.
Policy
Правила, которые относятся к модели, собирают в классе Policy:
php artisan make:policy PostPolicy --model=PostКаждый метод отвечает за одно действие и получает пользователя и модель:
namespace App\Policies;
use App\Models\Post;
use App\Models\User;
class PostPolicy
{
public function update(User $user, Post $post): bool
{
return $user->id === $post->user_id;
}
public function delete(User $user, Post $post): bool
{
return $user->id === $post->user_id || $user->is_admin;
}
public function create(User $user): bool
{
return $user->hasVerifiedEmail();
}
}Laravel сам находит Policy по имени модели: Post — PostPolicy.
Проверка в контроллере
use Illuminate\Support\Facades\Gate;
public function update(Request $request, Post $post)
{
Gate::authorize('update', $post);
$post->update($request->validated());
return redirect()->route('posts.show', $post);
}Если правило вернуло false, выполнение остановится с ошибкой 403. Для действий без модели передают класс: Gate::authorize('create', Post::class).
Проверка через пользователя
if ($request->user()->can('update', $post)) {
// ...
}
if ($request->user()->cannot('delete', $post)) {
abort(403);
}В шаблоне
Директива @can показывает блок только тем, кому действие разрешено:
@can('update', $post)
<a href="{{ route('posts.edit', $post) }}">Редактировать</a>
@endcan
@cannot('delete', $post)
<p>Удалить статью может только автор.</p>
@endcannotВ маршруте
Route::put('/posts/{post}', [PostController::class, 'update'])
->middleware('can:update,post');Администратор может всё
Метод before() выполняется раньше остальных правил Policy:
public function before(User $user): ?bool
{
return $user->is_admin ? true : null;
}null означает «решай обычным правилом».
Частая ошибка
Скрытая в шаблоне кнопка — не защита. Адрес можно набрать вручную или отправить запрос в обход интерфейса. Права обязательно проверяют на сервере: в контроллере, классе запроса или маршруте. Директива @can нужна только для удобства интерфейса.