Когда вы начинаете строить приложение на Laravel, рано или поздно возникает вопрос:
«Как контролировать, кто и что может делать?»
Например:
- Только автор статьи может её редактировать.
- Только администратор может удалять пользователей.
- Гость не должен видеть приватные данные.
Все эти проверки называются авторизацией (authorization), и Laravel предлагает для этого два основных механизма:
👉 Gates (ворота) и Policies (политики).
В этой статье мы подробно разберём Policies — что это, зачем они нужны, как их использовать и какие есть лучшие практики.
🧭 Что такое Policy в Laravel
Policy (политика) — это отдельный PHP-класс, в котором вы описываете правила доступа к конкретной модели.
Проще говоря: в Policy хранятся все правила, кто и что может делать с конкретным типом данных.
Например:
PostPolicyотвечает за доступ к постам (App\Models\Post),UserPolicy— за пользователей (App\Models\User),OrderPolicy— за заказы (App\Models\Order), и т.д.
Каждый метод политики описывает одно действие:
public function update(User $user, Post $post)
{
return $user->id === $post->user_id;
}
Этот метод говорит: «пользователь может редактировать пост только если он его автор».
🧩 Зачем нужны политики
Многие начинающие разработчики сначала просто вставляют проверки доступа прямо в контроллеры:
if ($post->user_id !== auth()->id()) {
abort(403);
}
Это работает, но со временем код превращается в кашу:
- Логика авторизации размазана по всем контроллерам;
- Повторяются одни и те же проверки;
- Изменить правило — значит искать и править в десятках мест.
Политики решают эту проблему.
Они позволяют:
- Вынести всю авторизацию в одно место;
- Сократить код контроллеров;
- Упростить тестирование;
- Сделать проект понятнее и масштабируемее.
🏁 Когда стоит использовать Policy
Используйте Policy, когда:
- Правила доступа зависят от модели (например, пост, заказ, комментарий);
- Есть разные действия над одной моделью (просмотр, обновление, удаление и т.д.);
- Вам нужно централизовать и повторно использовать проверки доступа.
А вот Gates лучше использовать, если проверка простая и не привязана к модели.
Например:
Gate::define('view-admin-dashboard', fn(User $user) => $user->is_admin);
🚀 Как начать использовать Policy в Laravel
Давайте создадим простую политику для модели Post.
1. Создаём политику
php artisan make:policy PostPolicy --model=Post
Laravel создаст файл:
app/Policies/PostPolicy.php
Содержимое будет примерно таким:
namespace App\Policies;
use App\Models\Post;
use App\Models\User;
class PostPolicy
{
public function viewAny(User $user): bool
{
return true;
}
public function view(User $user, Post $post): bool
{
return true;
}
public function create(User $user): bool
{
return true;
}
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;
}
}
2. Регистрируем политику
Laravel умеет автоматически находить политики, если вы соблюдаете стандартные имена:
Post → PostPolicy.
Если хотите указать вручную, откройте app/Providers/AuthServiceProvider.php:
protected $policies = [
\App\Models\Post::class => \App\Policies\PostPolicy::class,
];
3. Используем политику в контроллере
public function update(Request $request, Post $post)
{
$this->authorize('update', $post);
$post->update($request->all());
return redirect()->route('posts.show', $post);
}
Если пользователь не имеет права редактировать пост — Laravel выбросит исключение AuthorizationException (HTTP 403).
4. Используем политику в Blade
Laravel предоставляет удобную директиву @can:
@can('update', $post)
<a href="{{ route('posts.edit', $post) }}">Редактировать</a>
@endcan
или альтернативу:
@cannot('delete', $post)
<p>Вы не можете удалить этот пост</p>
@endcannot
5. Проверка через фасад Gate
Иногда полезно проверить доступ в сервисах или других местах, не связанных с контроллером:
if (Gate::allows('update', $post)) {
// пользователь может обновлять пост
}
или наоборот:
if (Gate::denies('delete', $post)) {
abort(403);
}
💡 Полезные методы и возможности
✅ before() — универсальная проверка
Иногда нужно дать администратору доступ ко всему.
Можно использовать метод before внутри политики:
public function before(User $user, string $ability)
{
if ($user->is_admin) {
return true;
}
}
Теперь админ может выполнять любое действие без дополнительных проверок.
🔄 Проверка нескольких действий
В Blade можно сразу проверить несколько правил:
@canany(['update', 'delete'], $post)
<p>Вы можете редактировать или удалять этот пост.</p>
@endcanany
🧱 Валидация на уровне маршрутов
Если вы используете Route Model Binding, Laravel может автоматически проверять доступ к модели:
Route::resource('posts', PostController::class)->middleware('can:update,post');
🧠 Лучшие практики
- Одна политика — одна модель.
Не мешайте в одном классе логику разных сущностей. - Не пишите бизнес-логику в политике.
Политика — только для проверки прав, не для изменения данных. - Используйте
before()для суперпользователей. - Всегда тестируйте политики.
Писать unit-тесты на политики легко, а баги в авторизации бывают дорогими. - Не дублируйте логику.
Если правило повторяется — вынесите его в отдельный метод или используйтеGate::before. - Будьте явными.
Лучше явно вызвать$this->authorize('update', $post), чем писать скрытые проверки.
🧩 Пример реальной ситуации
Допустим, у нас блог.
Требования:
- Автор может редактировать и удалять только свои посты.
- Админ может всё.
PostPolicy будет выглядеть так:
class PostPolicy
{
public function before(User $user, string $ability)
{
if ($user->is_admin) {
return true;
}
}
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;
}
}
Контроллер:
public function destroy(Post $post)
{
$this->authorize('delete', $post);
$post->delete();
return redirect()->route('posts.index');
}
И всё!
Laravel сам позаботится о безопасности и вернёт 403, если доступ запрещён.
🧭 Итог
Политики в Laravel — мощный и удобный инструмент, который:
- Делает код чище;
- Централизует авторизацию;
- Защищает от случайных ошибок;
- И легко интегрируется в контроллеры и шаблоны.
Если вы только начинаете — создайте хотя бы одну политику для своей основной модели и попробуйте использовать её вместо ручных if.
📘 Краткое резюме
| Что | Описание |
|---|---|
| Что такое Policy | Класс с правилами доступа для модели |
| Когда использовать | Когда проверка связана с конкретной моделью |
| Как вызвать | $this->authorize('update', $post) |
| В Blade | @can('update', $post) |
| Где хранится | app/Policies |
| Регистрируется | В AuthServiceProvider |
| Совет | Делайте логику прозрачной, пишите тесты |