Проверка разрешений в Policy классах Laravel магическими методами

Проведем рефакторинг классов политик и избавимся от лишнего кода с помощью пакета Laravel Policy Permission Check

Если вы работали с правами пользователя в 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 (по умолчанию).

Например, если ваше приложение использует точечную нотацию в ключах разрешений, то нужно изменить следующие параметры:

  1. permission.naming_rules.delimiters.between_words - установить на ..
  2. permission.naming_rules.delimiters.between_subject_and_action - установить на -.
  3. permission.naming_rules.key_pattern - установить на {subject}{delimiter}{action}.

Результат:

# Было
view any posts
 
# Стало
posts.view-any

Таким образом, можно настроить пакет к правилам наименования разрешений вашего приложения.

Дополнительные проверки

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

В этом методе можно обращаться к хелперу checkPermission():

  1. В первом аргументе передать $user.
  2. Во втором аргументе передать событие (если не передавать - будет проверяться разрешение на основе наименования вызываемого метода).
1 2 3 4 5 6 7 8
protected 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 17
class 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.

Комментарии

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: