Laravel: Gate и Policy

Laravel — популярный PHP-фреймворк широко используемый в веб-разработке. Он поставляется со встроенной системой авторизации позволяющей определять контроль доступа для разных пользователей и ролей. Двумя основными компонентами системы авторизации Laravel являются Gate и Policy. В этой статье мы рассмотрим концепцию Gate и Policy Laravel и то, как использовать их для защиты веб-приложений.

Что такое Laravel Gate

Laravel Gate — это простой способ определения правил контроля доступа. Он позволяет определять правила, определяющие, имеет ли пользователь право выполнять определённое действие или нет. Шлюз можно использовать для ограничения доступа к различным частям приложения на основе роли пользователя, разрешений или других критериев, которые вы определяете.

Шлюзы определяются в классе AuthServiceProvider, который находится в каталоге app/Providers. В методе boot класса AuthServiceProvider вы можете определить свои шлюзы используя фасад Gate предоставленный Laravel.

Пример определения Laravel шлюза проверяющий авторизован ли пользователь для обновления поста:

Gate::define('update-post', function ($user, $post) {
return $user->id === $post->user_id;
});

В приведённом выше коде мы определяем шлюз с именем update-post. Первый аргумент — это имя шлюза, а второй аргумент замыкание, определяющее логику шлюза. Замыкание принимает два аргумента: $user и $post. Аргумент $user — это аутентифицированный объект User, а аргумент $post — это объект Post, который пользователь хочет обновить.

Замыкание возвращает true, если пользователю разрешено обновлять пост, и false в противном случае. В этом примере мы проверяем, соответствует ли идентификатор пользователя идентификатору пользователя поста (прим.: автор поста?). Если они совпадают, мы возвращаем true, указывая, что пользователь авторизован для обновления поста.

Чтобы использовать Laravel Шлюз для маршрута, вы можете использовать middleware can, предоставляемое Laravel. Middleware can проверяет, авторизован ли аутентифицированный пользователь для выполнения определённого действия на основе определённого шлюза.

Пример использования шлюза Laravel для маршрута:

Route::get('/post/{post}', function (Post $post) {
// проверяем, может ли аутентифицированный пользователь обновить пост
if (Gate::allows('update-post', $post)) {
// возвращаем view для обновления поста
return view('update-post', ['post' => $post]);
} else {
// возвращаем ответ 403 Forbidden
abort(403);
}
})->middleware('can:update-post,post');

В приведённом выше коде мы определяем маршрут принимающий объект пост в качестве параметра. Прежде чем вернуть представление (view) для обновления поста, мы проверяем, может ли аутентифицированный пользователь обновить пост, используя метод Gate::allows(). Если пользователь авторизован для обновления сообщения, мы возвращаем представление для обновления сообщения. Если нет, возвращаем ответ 403 Forbidden.

Для большей эффективности мы можем использовать middleware can для автоматической проверки, авторизован ли пользователь для выполнения действия определённого в шлюзе. В приведённом выше примере мы добавили middleware('can:update-post,post') к определению маршрута. Это middleware автоматически проверяет, может ли аутентифицированный пользователь обновить пост с помощью шлюза update-post. Если пользователь авторизован, middleware продолжит выполнять обработчик маршрута. Если нет, middleware вернёт ответ 403 Forbidden.

Использование middleware can — удобный способ защитить маршруты с помощью Laravel шлюзов. Это позволяет определять правила управления доступом в центральной локации и применять их к нескольким маршрутам в приложении.

Что такое Laravel Policy

Политики Laravel похожи на шлюзы, но более мощные и гибкие. Политики позволяют определить логику авторизации для конкретной модели или ресурса. Например, вы можете определить политику для модели Post, которая определяет правила управления доступом для создания, обновления, удаления и просмотра постов.

Как и шлюзы, политики Laravel определяются в классе AuthServiceProvider. Однако вместо определения замыкания вы определяете классы политики инкапсулирующие логику авторизации для конкретной модели или ресурса.

Пример определения Laravel политики для модели Post:

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

В приведённом выше коде мы определяем класс политики с именем PostPolicy. У класса есть публичный метод update принимающий два аргумента: $user и $post. Аргумент $user — это аутентифицированный объект User, а аргумент $post — это объект Post, который пользователь хочет обновить.

Метод update возвращает true, если пользователь имеет право обновлять пост, и false в противном случае. В этом примере мы проверяем, соответствует ли идентификатор пользователя идентификатору пользователя поста (прим. автор поста?). Если они совпадают, мы возвращаем true, указывая, что пользователь авторизован для обновления поста.

Для использования класса PostPolicy его необходимо зарегистрировать в классе AuthServiceProvider:

protected $policies = [
Post::class => PostPolicy::class,
];

В приведённом выше коде мы регистрируем модель Post с соответствующим классом политики PostPolicy. Теперь Laravel знает, что необходимо использовать класс PostPolicy для авторизации действий в модели Post.

Для использования политики в контроллере, необходимо сначала авторизовать запрос пользователя с помощью политики. Laravel предоставляет метод authorize, который вы можете вызвать для авторизации запроса пользователя перед выполнением метода контроллера.

Пример использования Laravel политики в контроллере:

use App\Models\Post;
use Illuminate\Http\Request;

class PostController extends Controller
{
public function update(Request $request, Post $post)
{
$this->authorize('update', $post);

// обновление поста
}
}

В приведённом выше примере кода мы определяем PostController с методом update принимающим два аргумента: $request и $post. Аргумент $request — экземпляр класса Illuminate\Http\Request, а аргумент $post — пост, который пользователь хочет обновить.

Перед обновлением поста мы вызываем метод authorize и передаём имя метода политики, который хотим использовать (update), и объект $post, для которого хотим авторизовать пользователя. Laravel будет автоматически искать соответствующий метод политики (update) в классе политик (PostPolicy), который мы зарегистрировали в AuthServiceProvider.

Если пользователю разрешено обновление поста, метод контроллера продолжит выполнение. Если нет, Laravel автоматически выдаст исключение 403 Forbidden.

Использование политик в контроллерах — мощный способ гарантировать, что только авторизованные пользователи могут получить доступ к определённым ресурсам или выполнить определённые действия. Это позволяет инкапсулировать логику авторизации в класс политики и поддерживать чистоту и читабельность кода контроллера.

Дополнительные материалы

Предыдущая Статья

Laravel аналитика. Зачем и как я сделал свой пакет

Следующая Статья

Новое в Symfony 6.3 — Улучшения Dependency Injection