Если вы работали с правами пользователя в Laravel, то наверняка вы использовали не только ворота (Gates), но и классы политик (Policy).
В некоторых ситуациях, методы политики действуют по одному и тому же принципу - условия работают крайне похоже:
Я сделал небольшой пакет, который предоставляет доступ к абстрактному классу MagicPolicy. Отнаследуйте ваши классы политики от него и ваш код сократится, а также он станет более удобным в поддержке.
На примере, который представлен на картинке выше, финальный код (при использовании моего пакета) будет таким:
Laravel Policy Permission Check
Установка и подключение пакета
Необходимо установить пакет с помощью composer:
composer require sarvarov/laravel-policy-permission-check
После этого необходимо лишь выполнить наследование отSarvarov\LaravelPolicyPermissionCheck\MagicPolicy в файле класса политики:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15<?php namespace App\Models\Policies; use App\Models\Auth\User; use App\Models\Post; use Illuminate\Auth\Access\HandlesAuthorization; use Sarvarov\LaravelPolicyPermissionCheck\MagicPolicy; class PostPolicy extends MagicPolicy { use HandlesAuthorization; /* ... */ }
Магические методы
Если вы сверяете просто наличие доступа пользователя какому-то действию, то пакет самостоятельно найдет соответствующее разрешение, беря за основу название метода.
Например, если отнаследоваться от MagicPolicy, то следующий метод политики можно будет удалить (он излишний):
public function update(User $user, Post $post)
{
return $user->can('update posts');
}
По умолчанию пытается найти разрешение по следующему ключу: событие + пробел + модель во множественном числе:
view any posts
view posts
create posts
update posts
delete posts
# и так далее...
Если вы используете другой формат названия разрешений, то измените их, отредактировав следующие настройки:
- permission.naming_rules.subject_plural - возводить ли название модели во множественное число.
Пример (если установить false): то будет view post, а не view posts (по умолчанию). - permission.naming_rules.delimiters.between_words - разделитель слов в названии разрешения.
Пример (если установить -): то будет view-any blog-posts, а не view any blog posts (по умолчанию). - permission.naming_rules.delimiters.between_subject_and_action - разделитель между действием и моделью.
Пример (если установить .): то будет posts.view, а не posts view (по умолчанию). - permission.naming_rules.key_pattern - порядок элементов в ключе разрешения.
Пример, если установить {subject}{delimiter}{action}: то будет posts view any, а не view any posts (по умолчанию).
Например, если ваше приложение использует точечную нотацию в ключах разрешений, то нужно изменить следующие параметры:
- permission.naming_rules.delimiters.between_words - установить на ..
- permission.naming_rules.delimiters.between_subject_and_action - установить на -.
- permission.naming_rules.key_pattern - установить на {subject}{delimiter}{action}.
Результат:
# Было
view any posts
# Стало
posts.view-any
Таким образом, можно настроить пакет к правилам наименования разрешений вашего приложения.
Дополнительные проверки
Если, помимо разрешения, необходимо выполнить какие-то дополнительные проверки на прохождения условия, то нужно создать соответствующий метод в классе политики.
В этом методе можно обращаться к хелперу checkPermission():
- В первом аргументе передать $user.
- Во втором аргументе передать событие (если не передавать - будет проверяться разрешение на основе наименования вызываемого метода).
1 2 3 4 5 6 7 8protected function delete(User $user, Post $post) { if ($user->id === $post->author_id) { return $this->checkPermission($user, 'delete own posts'); } return $this->checkPermission($user); }
Прокси-методы
Если у вас повторяется код нескольких методов, то можно использовать прокси-методы.
Для этого нужно создать массив - защищенное свойство $proxies в классе политики.
Ключ элементов этого массива является название метода, куда будет идти перенаправление с вызываемого метода. Значение этих элементов будет массивом названий прокси-методов (методов с которых перенаправлять):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44// Было: class PostPolicy extends MagicPolicy { use HandlesAuthorization; protected function update(User $user, Post $post) { if ($user->id === $post->author_id) { return $this->checkPermission($user, 'update own'); } return $this->checkPermission($user); } protected function delete(User $user, Post $post) { if ($user->id === $post->author_id) { return $this->checkPermission($user, 'delete own'); } return $this->checkPermission($user); } } // Стало: class PostPolicy extends MagicPolicy { use HandlesAuthorization; protected $proxies = [ 'manage' => ['update', 'delete'], ]; protected function manage(User $user, Post $post) { if ($user->id === $post->author_id) { return $this->checkProxiedPermission($user, 'own'); // проверяет на `update own posts` и `delete own posts` } return $this->checkPermission($user); // проверяет на `update posts` и `delete posts` } }
По умолчанию, идёт сравнение разрешений по названию прокси-методов, однако это можно переопределить, добавив :false к ключу к элементу(ам) в свойстве $proxies:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17class PostPolicy extends MagicPolicy { use HandlesAuthorization; protected $proxies = [ 'manage:false' => ['update', 'delete'], ]; protected function manage(User $user, Post $post) { if ($user->id === $post->author_id) { return $this->checkProxiedPermission($user, 'own'); // всегда проверяет на `manage own posts` } return $this->checkPermission($user); // всегда проверяет на `manage posts` } }
Управление настройками
Чтобы изменить настройки пакета, нужно создать файл /config/permission.php. Внутри этого файла нужно возвращать массив с параметрами.
Все параметры можно найти в файлах пакета: MagicPermission.php и PermissionCheckHelper.php.
Понравилось прочитанное?
Дайте мне «пять», кликнув раз, или же поаплодируйте быстрыми нажатиями, чтобы показать, насколько вам понравился материал.
Комментарии