Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Права доступа

Аутентификация отвечает на вопрос «кто это?», авторизация — «что ему можно?». Вошедший пользователь не должен редактировать чужие статьи. 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'); // при отказе — ошибка 403

Gate подходит для правил, не привязанных к конкретной модели.

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 нужна только для удобства интерфейса.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.