1. Безопасность
  2. Авторизация

Присоединяйся к нашему Telegram сообществу @webblend!

Здесь ты найдешь сниппеты по Laravel и полезные советы по веб-разработке.

Введение

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

Laravel предоставляет два основных способа авторизации действий: ворота и политики. Подумайте о воротах и политиках как о маршрутах и контроллерах. Ворота предоставляют простой, основанный на замыканиях подход к авторизации, в то время как политики, как контроллеры, группируют логику вокруг конкретной модели или ресурса. В этой документации мы рассмотрим ворота сначала, а затем изучим политики.

Вам не нужно выбирать между исключительным использованием ворот или исключительным использованием политик при построении приложения. Вероятно, большинство приложений будут содержать некоторую смесь ворот и политик, и это вполне нормально! Ворота наиболее применимы к действиям, не связанным с какой-либо моделью или ресурсом, например, просмотр панели администратора. В отличие от этого, политики следует использовать, когда вы хотите авторизовать действие для конкретной модели или ресурса.

Шлюзы

Написание шлюзов

Внимание Ворота - отличный способ изучить основы функций авторизации Laravel. Тем не менее, при создании надежных приложений Laravel рекомендуется использовать политики для организации ваших правил авторизации.

Ворота - это просто замыкания, которые определяют, разрешено ли пользователю выполнить данное действие. Обычно ворота определяются внутри метода boot класса App\Providers\AuthServiceProvider с использованием фасада Gate. Ворота всегда получают экземпляр пользователя в качестве своего первого аргумента и при необходимости могут получать дополнительные аргументы, такие как соответствующая модель Eloquent.

В этом примере мы определим ворота, чтобы определить, может ли пользователь обновить данную модель App\Models\Post. Ворота будут выполнять это, сравнивая id пользователя с user_id пользователя, создавшего запись:

use App\Models\Post;
use App\Models\User;
use Illuminate\Support\Facades\Gate;
 
/**
* Зарегистрируйте любые службы аутентификации / авторизации.
*/
public function boot(): void
{
Gate::define('update-post', function (User $user, Post $post) {
return $user->id === $post->user_id;
});
}

Как и контроллеры, ворота также можно определять с использованием массива обратного вызова класса:

use App\Policies\PostPolicy;
use Illuminate\Support\Facades\Gate;
 
/**
* Зарегистрируйте любые службы аутентификации / авторизации.
*/
public function boot(): void
{
Gate::define('update-post', [PostPolicy::class, 'update']);
}

Авторизация действий

Для авторизации действия с использованием ворот вы должны использовать методы allows или denies, предоставляемые фасадом Gate. Обратите внимание, что вы не обязаны передавать текущего аутентифицированного пользователя этим методам. Laravel автоматически обеспечивает передачу пользователя в замыкание ворот. Обычно вызывать методы авторизации ворот следует в контроллерах вашего приложения перед выполнением действия, требующего авторизации:

<?php
 
namespace App\Http\Controllers;
 
use App\Http\Controllers\Controller;
use App\Models\Post;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;
 
class PostController extends Controller
{
/**
* Обновить данный пост.
*/
public function update(Request $request, Post $post): RedirectResponse
{
if (! Gate::allows('update-post', $post)) {
abort(403);
}
 
// Обновление записи...
 
return redirect('/posts');
}
}

Если вы хотите определить, разрешено ли выполнение действия пользователем, отличным от текущего аутентифицированного пользователя, вы можете использовать метод forUser в фасаде Gate:

if (Gate::forUser($user)->allows('update-post', $post)) {
// Пользователь может обновлять запись...
}
 
if (Gate::forUser($user)->denies('update-post', $post)) {
// Пользователь не может обновлять запись...
}

Вы можете авторизовать несколько действий одновременно, используя методы any или none:

if (Gate::any(['update-post', 'delete-post'], $post)) {
// Пользователь может обновлять или удалять запись...
}
 
if (Gate::none(['update-post', 'delete-post'], $post)) {
// Пользователь не может обновлять или удалять запись...
}

Авторизация или выброс исключений

Если вы хотите попытаться авторизовать действие и автоматически выбросить исключение Illuminate\Auth\Access\AuthorizationException, если пользователю не разрешено выполнение данного действия, вы можете использовать метод authorize фасада Gate. Экземпляры AuthorizationException автоматически преобразуются в ответ HTTP 403 обработчиком исключений Laravel:

Gate::authorize('update-post', $post);

// Действие авторизовано...

Предоставление дополнительного контекста

Методы ворот для авторизации возможностей (allows, denies, check, any, none, authorize, can, cannot) и директивы шаблона авторизации (@can, @cannot, @canany) могут принимать массив в качестве своего второго аргумента. Элементы этого массива передаются в замыкание ворот и могут использоваться для дополнительного контекста при принятии решения об авторизации:

use App\Models\Category;
use App\Models\User;
use Illuminate\Support\Facades\Gate;
 
Gate::define('create-post', function (User $user, Category $category, bool $pinned) {
if (! $user->canPublishToGroup($category->group)) {
return false;
} elseif ($pinned && ! $user->canPinPosts()) {
return false;
}
 
return true;
});
 
if (Gate::check('create-post', [$category, $pinned])) {
// Пользователь может создавать запись...
}

Ответы шлюза

До сих пор мы рассматривали только ворота, возвращающие простые булевы значения. Тем не менее иногда вам может потребоваться возвращать более подробный ответ, включая сообщение об ошибке. Для этого вы можете возвращать Illuminate\Auth\Access\Response из вашего ворота:

use App\Models\User;
use Illuminate\Auth\Access\Response;
use Illuminate\Support\Facades\Gate;
 
Gate::define('edit-settings', function (User $user) {
return $user->isAdmin
? Response::allow()
: Response::deny('Вы должны быть администратором.');
});

Даже когда вы возвращаете ответ авторизации из вашего ворота, метод Gate::allows по-прежнему вернет простое булево значение; однако вы можете использовать метод Gate::inspect для получения полного ответа авторизации, возвращаемого воротами:

$response = Gate::inspect('edit-settings');
 
if ($response->allowed()) {
// Действие авторизовано...
} else {
echo $response->message();
}

При использовании метода Gate::authorize, который выбрасывает исключение AuthorizationException, если действие не авторизовано, сообщение об ошибке, предоставленное ответом авторизации, будет передано в HTTP-ответ:

Gate::authorize('edit-settings');

// Действие авторизовано...

Настройка HTTP-статуса ответа

Когда доступ к действию запрещен через ворота, возвращается HTTP-ответ 403; однако иногда полезно возвращать альтернативный код статуса HTTP. Вы можете настроить код статуса HTTP, возвращаемый для неудачной проверки авторизации, используя статический конструктор denyWithStatus класса Illuminate\Auth\Access\Response:

use App\Models\User;
use Illuminate\Auth\Access\Response;
use Illuminate\Support\Facades\Gate;
 
Gate::define('edit-settings', function (User $user) {
return $user->isAdmin
? Response::allow()
: Response::denyWithStatus(404);
});

Поскольку скрытие ресурсов через ответ 404 является таким распространенным шаблоном для веб-приложений, предлагается метод denyAsNotFound для удобства:

use App\Models\User;
use Illuminate\Auth\Access\Response;
use Illuminate\Support\Facades\Gate;
 
Gate::define('edit-settings', function (User $user) {
return $user->isAdmin
? Response::allow()
: Response::denyAsNotFound();
});

Перехват проверок шлюза

Иногда вам может потребоваться предоставить все возможности конкретному пользователю. Вы можете использовать метод before для определения замыкания, которое выполняется перед всеми остальными проверками авторизации:

use App\Models\User;
use Illuminate\Support\Facades\Gate;
 
Gate::before(function (User $user, string $ability) {
if ($user->isAdministrator()) {
return true;
}
});

Если замыкание before возвращает ненулевой результат, этот результат будет считаться результатом проверки авторизации.

Вы можете использовать метод after для определения замыкания, которое будет выполнено после всех остальных проверок авторизации:

use App\Models\User;
 
Gate::after(function (User $user, string $ability, bool|null $result, mixed $arguments) {
if ($user->isAdministrator()) {
return true;
}
});

Как и метод before, если замыкание after возвращает ненулевой результат, этот результат будет считаться результатом проверки авторизации.

Встроенная авторизация

Иногда вам может потребоваться определить, разрешено ли выполнение данного действия текущим аутентифицированным пользователем, не создавая отдельного ворота, который соответствует данному действию. Laravel позволяет выполнять такие проверки авторизации "встроенно" с использованием методов Gate::allowIf и Gate::denyIf:

use App\Models\User;
use Illuminate\Support\Facades\Gate;
 
Gate::allowIf(fn (User $user) => $user->isAdministrator());
 
Gate::denyIf(fn (User $user) => $user->banned());

Если действие не разрешено или если текущий пользователь не аутентифицирован, Laravel автоматически выбросит исключение Illuminate\Auth\Access\AuthorizationException. Экземпляры AuthorizationException автоматически преобразуются в ответ HTTP 403 обработчиком исключений Laravel.

Создание политик

Генерация политик

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

Вы можете создать политику, используя команду Artisan make:policy. Сгенерированная политика будет помещена в каталог app/Policies. Если этот каталог отсутствует в вашем приложении, Laravel создаст его для вас:

php artisan make:policy PostPolicy

Команда make:policy сгенерирует пустой класс политики. Если вы хотите сгенерировать класс с примерными методами политики, касающимися просмотра, создания, обновления и удаления ресурса, вы можете предоставить опцию --model при выполнении команды:

php artisan make:policy PostPolicy --model=Post

Регистрация политик

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

Включенный во Fresh Laravel-приложения App\Providers\AuthServiceProvider содержит свойство policies, которое сопоставляет ваши Eloquent-модели с соответствующими политиками. Регистрация политики инструктирует Laravel, какую политику использовать для авторизации действий по отношению к определенной модели Eloquent:

<?php
 
namespace App\Providers;
 
use App\Models\Post;
use App\Policies\PostPolicy;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Gate;
 
class AuthServiceProvider extends ServiceProvider
{
/**
* Сопоставления политик для приложения.
*
* @var array
*/
protected $policies = [
Post::class => PostPolicy::class,
];
 
/**
* Зарегистрируйте любые службы аутентификации / авторизации приложения.
*/
public function boot(): void
{
// ...
}
}

Автоопределение политик

Вместо ручной регистрации политик моделей Laravel может автоматически обнаруживать политики, если модель и политика следуют стандартным соглашениям именования Laravel. В частности, политики должны находиться в каталоге Policies в или выше каталога, содержащего ваши модели. Так, например, модели могут быть размещены в каталоге app/Models, а политики - в каталоге app/Policies. В этой ситуации Laravel проверит политики в app/Models/Policies, затем в app/Policies. Кроме того, имя политики должно соответствовать имени модели и иметь суффикс Policy. Так, например, модель User будет соответствовать классу политики UserPolicy.

Если вы хотите определить свою собственную логику обнаружения политик, вы можете зарегистрировать пользовательский обратный вызов обнаружения политики с использованием метода Gate::guessPolicyNamesUsing. Обычно этот метод следует вызывать из метода boot провайдера аутентификации вашего приложения:

use Illuminate\Support\Facades\Gate;
 
Gate::guessPolicyNamesUsing(function (string $modelClass) {
// Вернуть имя класса политики для заданной модели...
});

Внимание Любые политики, явно сопоставленные в вашем AuthServiceProvider, будут иметь приоритет перед любыми возможно обнаруженными автоматически политиками.

Написание политик

Методы политики

После того как класс политики зарегистрирован, вы можете добавить методы для каждого действия, которое он авторизует. Например, давайте определим метод update в нашей политике PostPolicy, который определит, может ли данный пользователь App\Models\User обновить данный экземпляр App\Models\Post.

Метод update будет получать User и экземпляр Post в качестве своих аргументов и должен возвращать true или false, указывая, разрешено ли пользователю обновлять данный Post. Таким образом, в этом примере мы будем проверять, совпадает ли id пользователя с user_id записи:

<?php
 
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;
}
}

Вы можете продолжить определение дополнительных методов в политике по мере необходимости для различных действий, которые она авторизует. Например, вы можете определить методы view или delete для авторизации различных действий, связанных с Post, но помните, что вы можете дать своим методам политики любые имена, которые вам нравятся.

Если вы использовали опцию --model при генерации политики через Artisan Console, она уже будет содержать методы для действий viewAny, view, create, update, delete, restore и forceDelete.

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

Ответы политики

До сих пор мы рассматривали только методы политики, возвращающие простые булевы значения. Однако иногда вы можете захотеть вернуть более подробный ответ, включая сообщение об ошибке. Для этого вы можете вернуть экземпляр Illuminate\Auth\Access\Response из вашего метода политики:

use App\Models\Post;
use App\Models\User;
use Illuminate\Auth\Access\Response;
 
/**
* Определить, может ли данный пост быть обновлен пользователем.
*/
public function update(User $user, Post $post): Response
{
return $user->id === $post->user_id
? Response::allow()
: Response::deny('У вас нет прав на изменение этого сообщения.');
}

При возврате ответа на авторизацию из вашей политики метод Gate::allows по-прежнему вернет простое булево значение; однако вы можете использовать метод Gate::inspect для получения полного ответа на авторизацию, возвращаемого воротами:

use Illuminate\Support\Facades\Gate;
 
$response = Gate::inspect('update', $post);
 
if ($response->allowed()) {
// Действие авторизовано...
} else {
echo $response->message();
}

При использовании метода Gate::authorize, который выбрасывает исключение AuthorizationException, если действие не разрешено, сообщение об ошибке, предоставленное ответом на авторизацию, будет передано в HTTP-ответ:

Gate::authorize('update', $post);

// Действие авторизовано...

Настройка HTTP-статуса ответа

Когда действие отклонено с использованием метода политики, возвращается HTTP-ответ 403; однако иногда может быть полезно вернуть альтернативный код состояния HTTP. Вы можете настроить код состояния HTTP, возвращаемый при неудачной проверке авторизации, с использованием статического конструктора denyWithStatus в классе Illuminate\Auth\Access\Response:

use App\Models\Post;
use App\Models\User;
use Illuminate\Auth\Access\Response;
 
/**
* Определить, может ли данный пост быть обновлен пользователем.
*/
public function update(User $user, Post $post): Response
{
return $user->id === $post->user_id
? Response::allow()
: Response::denyWithStatus(404);
}

Поскольку скрытие ресурсов с использованием ответа 404 является таким распространенным шаблоном для веб-приложений, предоставляется метод denyAsNotFound для удобства:

use App\Models\Post;
use App\Models\User;
use Illuminate\Auth\Access\Response;
 
/**
* Определить, может ли данный пост быть обновлен пользователем.
*/
public function update(User $user, Post $post): Response
{
return $user->id === $post->user_id
? Response::allow()
: Response::denyAsNotFound();
}

Методы без моделей

Некоторые методы политики получают только экземпляр текущего аутентифицированного пользователя. Это наиболее распространено при авторизации действий create. Например, если вы создаете блог, вам может потребоваться определить, разрешено ли пользователю вообще создавать записи. В этих ситуациях метод политики должен ожидать только экземпляр пользователя:

/**
* Определить, может ли данный пользователь создавать записи.
*/
public function create(User $user): bool
{
return $user->role == 'writer';
}

Гостевые пользователи

По умолчанию все ворота и политики автоматически возвращают false, если входной HTTP-запрос не был инициирован аутентифицированным пользователем. Однако вы можете разрешить прохождение этих проверок авторизации через ваши ворота и политики, объявив тип-подсказку "optional" или предоставив значение null по умолчанию для определения аргумента пользователя:

<?php
 
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;
}
}

Фильтры политик

Для определенных пользователей может потребоваться разрешить все действия в рамках определенной политики. Для этого определите метод before в политике. Метод before будет выполнен перед любыми другими методами политики, предоставляя вам возможность авторизовать действие перед тем, как вызывается фактический метод политики.

use App\Models\User;
 
/**
* Выполнить предварительные проверки авторизации.
*/
public function before(User $user, string $ability): bool|null
{
if ($user->isAdministrator()) {
return true;
}
 
return null;
}

Если вы хотите отклонить все проверки авторизации для определенного типа пользователя, вы можете вернуть false из метода before. Если возвращается null, проверка авторизации будет передана методу политики.

Внимание Метод before класса политики не будет вызван, если в классе нет метода с именем, совпадающим с именем проверяемой способности.

Авторизация действий с использованием политик

Через модель пользователя

Модель App\Models\User, включенная в ваше приложение Laravel, содержит два полезных метода для авторизации действий: can и cannot. Методы can и cannot получают имя действия, которое вы хотите авторизовать, и соответствующую модель. Например, давайте определим, разрешено ли пользователю обновлять данную модель App\Models\Post. Обычно это будет сделано внутри метода контроллера:

<?php
 
namespace App\Http\Controllers;
 
use App\Http\Controllers\Controller;
use App\Models\Post;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
 
class PostController extends Controller
{
/**
* Обновить данный пост.
*/
public function update(Request $request, Post $post): RedirectResponse
{
if ($request->user()->cannot('update', $post)) {
abort(403);
}
 
// Обновление записи...
 
return redirect('/posts');
}
}

Если для данной модели зарегистрирована политика, метод can автоматически вызовет соответствующую политику и вернет булев результат. Если для модели не зарегистрирована политика, метод can попытается вызвать замыкание ворот, соответствующее заданному имени действия.

Действия, которые не требуют моделей

Помните, что некоторые действия могут соответствовать методам политики, таким как create, которым не требуется экземпляр модели. В этих ситуациях вы можете передать имя класса методу can. Имя класса будет использоваться для определения, какую политику использовать при авторизации действия:

<?php
 
namespace App\Http\Controllers;
 
use App\Http\Controllers\Controller;
use App\Models\Post;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
 
class PostController extends Controller
{
/**
* Создать запись.
*/
public function store(Request $request): RedirectResponse
{
if ($request->user()->cannot('create', Post::class)) {
abort(403);
}
 
// Создание записи...
 
return redirect('/posts');
}
}

Через вспомогательные функции контроллера

Помимо полезных методов, предоставленных модели App\Models\User, Laravel предоставляет полезный метод authorize любым вашим контроллерам, которые расширяют базовый класс App\Http\Controllers\Controller.

Как и метод can, этот метод принимает имя действия, которое вы хотите авторизовать, и соответствующую модель. Если действие не разрешено, метод authorize выбросит исключение Illuminate\Auth\Access\AuthorizationException, которое обработчик исключений Laravel автоматически преобразует в HTTP-ответ с кодом состояния 403:

<?php
 
namespace App\Http\Controllers;
 
use App\Http\Controllers\Controller;
use App\Models\Post;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
 
class PostController extends Controller
{
/**
* Обновить данный блог-пост.
*
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function update(Request $request, Post $post): RedirectResponse
{
$this->authorize('update', $post);
 
// Текущий пользователь может обновить блог-пост...
 
return redirect('/posts');
}
}

Действия, которые не требуют моделей

Как ранее обсуждалось, некоторые методы политики, такие как create, не требуют экземпляра модели. В этих ситуациях вы должны передать имя класса методу authorize. Имя класса будет использоваться для определения, какую политику использовать при авторизации действия:

use App\Models\Post;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
 
/**
* Создать новый блог-пост.
*
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function create(Request $request): RedirectResponse
{
$this->authorize('create', Post::class);
 
// Текущий пользователь может создавать блог-посты...
 
return redirect('/posts');
}

Авторизация контроллеров ресурсов

Если вы используете ресурсные контроллеры, вы можете воспользоваться методом authorizeResource в конструкторе контроллера. Этот метод добавит соответствующие определения промежуточного программного обеспечения can для методов контроллера ресурсов.

Метод authorizeResource принимает имя класса модели в качестве первого аргумента и имя маршрута / параметра запроса, который будет содержать идентификатор модели, в качестве второго аргумента. Вы должны убедиться, что ваш ресурсный контроллер создан с использованием флага --model, чтобы он имел необходимые сигнатуры методов и подсказки типа:

<?php
 
namespace App\Http\Controllers;
 
use App\Http\Controllers\Controller;
use App\Models\Post;
 
class PostController extends Controller
{
/**
* Создать экземпляр контроллера.
*/
public function __construct()
{
$this->authorizeResource(Post::class, 'post');
}
}

Следующие методы контроллера будут сопоставлены соответствующим методам политики. Когда запросы маршрутизируются к заданному методу контроллера, соответствующий метод политики будет автоматически вызван перед выполнением метода контроллера:

Метод контроллера Метод политики
index viewAny
show view
create create
store create
edit update
update update
destroy delete

Примечание Вы можете использовать команду make:policy с опцией --model, чтобы быстро сгенерировать класс политики для заданной модели: php artisan make:policy PostPolicy --model=Post.

Через промежуточное ПО

Laravel включает промежуточное программное обеспечение, которое может авторизовывать действия до того, как входящий запрос даже достигнет ваших маршрутов или контроллеров. По умолчанию промежуточному программному обеспечению Illuminate\Auth\Middleware\Authorize присваивается ключ can в вашем классе App\Http\Kernel. Давайте рассмотрим пример использования промежуточного программного обеспечения can для авторизации пользователя на обновление сообщения:

use App\Models\Post;
 
Route::put('/post/{post}', function (Post $post) {
// Текущий пользователь может обновить запись...
})->middleware('can:update,post');

В этом примере мы передаем промежуточному программному обеспечению can два аргумента. Первый - это имя действия, которое мы хотим авторизовать, и второй - это параметр маршрута, который мы хотим передать методу политики. В данном случае, поскольку мы используем неявную привязку модели, модель App\Models\Post будет передана методу политики. Если пользователь не авторизован на выполнение заданного действия, промежуточное программное обеспечение вернет HTTP-ответ с кодом состояния 403.

Для удобства вы также можете прикрепить промежуточное программное обеспечение can к вашему маршруту с использованием метода can:

use App\Models\Post;
 
Route::put('/post/{post}', function (Post $post) {
// Текущий пользователь может обновить запись...
})->can('update', 'post');

Действия, которые не требуют моделей

Опять же, некоторые методы политики, такие как create, не требуют экземпляра модели. В этих ситуациях вы можете передать имя класса в промежуточное программное обеспечение. Имя класса будет использоваться для определения, какую политику использовать при авторизации действия:

Route::post('/post', function () {
// Текущий пользователь может создавать записи...
})->middleware('can:create,App\Models\Post');

Указание полного имени класса в строковом определении промежуточного программного обеспечения может стать неудобным. По этой причине вы можете выбрать прикрепление промежуточного программного обеспечения can к вашему маршруту с использованием метода can:

use App\Models\Post;
 
Route::post('/post', function () {
// Текущий пользователь может создавать записи...
})->can('create', Post::class);

Через шаблоны Blade

При написании шаблонов Blade вы можете захотеть отображать часть страницы только в том случае, если пользователь авторизован на выполнение заданного действия. Например, вы можете показать форму обновления для сообщения блога только в том случае, если пользователь действительно может обновить сообщение. В этой ситуации вы можете использовать директивы @can и @cannot:

@can('update', $post)
<!-- Текущий пользователь может обновить сообщение... -->
@elsecan('create', App\Models\Post::class)
<!-- Текущий пользователь может создавать новые сообщения... -->
@else
<!-- ... -->
@endcan
 
@cannot('update', $post)
<!-- Текущий пользователь не может обновить сообщение... -->
@elsecannot('create', App\Models\Post::class)
<!-- Текущий пользователь не может создавать новые сообщения... -->
@endcannot

Эти директивы представляют собой удобные ярлыки для написания операторов @if и @unless. Утверждения @can и @cannot выше эквивалентны следующим утверждениям:

@if (Auth::user()->can('update', $post))
<!-- Текущий пользователь может обновить сообщение... -->
@endif
 
@unless (Auth::user()->can('update', $post))
<!-- Текущий пользователь не может обновить сообщение... -->
@endunless

Вы также можете определить, авторизован ли пользователь для выполнения любого действия из данного массива действий. Для этого используйте директиву @canany:

@canany(['update', 'view', 'delete'], $post)
<!-- Текущий пользователь может обновлять, просматривать или удалять сообщение... -->
@elsecanany(['create'], \App\Models\Post::class)
<!-- Текущий пользователь может создать сообщение... -->
@endcanany

Действия, которые не требуют моделей

Как и в большинстве других методов авторизации, вы можете передать имя класса директивам @can и @cannot, если действие не требует экземпляра модели:

@can('create', App\Models\Post::class)
<!-- Текущий пользователь может создавать сообщения... -->
@endcan
 
@cannot('create', App\Models\Post::class)
<!-- Текущий пользователь не может создавать сообщения... -->
@endcannot

Предоставление дополнительного контекста

При авторизации действий с использованием политик вы можете передать массив вторым аргументом в различные функции и вспомогательные функции авторизации. Первый элемент массива будет использоваться для определения, какую политику следует вызывать, в то время как остальные элементы массива передаются в метод политики в качестве параметров и могут использоваться для предоставления дополнительного контекста при принятии решения об авторизации. Например, рассмотрим следующее определение метода PostPolicy, который содержит дополнительный параметр $category:

/**
* Определить, может ли данный пост быть обновлен пользователем.
*/
public function update(User $user, Post $post, int $category): bool
{
return $user->id === $post->user_id &&
$user->canUpdateCategory($category);
}

При попытке определить, может ли аутентифицированный пользователь обновить заданное сообщение, мы можем вызвать этот метод политики следующим образом:

/**
* Обновить данный блог-пост.
*
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function update(Request $request, Post $post): RedirectResponse
{
$this->authorize('update', [$post, $request->category]);
 
// Текущий пользователь может обновить блог-пост...
 
return redirect('/posts');
}