Перейти к основному содержимому

Ролевая модель и права доступа в АП

Текущая реализация ролевой модели и прав доступа позволяет создавать неограниченное число ролей, назначать им любые права доступа и привязывать произвольный набор ролей к пользователю. Для этого в административной панели предусмотрен конструктор прав доступа при создании/редактировании роли.

Как работают права доступа

На бэкенде

Набор возможных прав доступа хранится в enum в units/admin-auth. Затем используется симбиоз из Laravel features: Policies, Gates, Middleware в admin-gui-backend:

  1. Связь прав с методами (эндпоинтами) хранится в политиках
  2. Метод в политике описывает права на доступ к аналогичному (по неймингу) методу в контроллере
  3. 1 политика – 1 контроллер
  4. Через фасад Gate проверяется политика в Middleware при запросе API
  5. В зависимости от выполнения условия описанного в методе политики для этого контроллера@метода API – доступ либо предоставляется, либо выбрасывается 403 ошибка

Автоматический поиск политик работает по такому принципу:

Gate::guessPolicyNamesUsing(
fn ($className) => str_replace('Controllers', 'Policies', $className) . 'Policy'
);

На фронте

Для фронта справочник прав доступа возращается методом: GET /api/v1/units/admin-users/right-access. Фронт сравнивает набор прав доступа текущего пользователя со справочником, исходя из этого допускает пользователя к тем или иным действиям.

Добавление прав доступа

Сначала нужно добавить новые права в rights_access_enum.yaml:

  description: |
* `9xx` Для информационных страниц:
* `901` - Пользователю доступен табличный список с информационными страницами
* `902` - Пользователю доступна детальная страница информационной страницы
enum:
- 901
- 902
x-enum-varnames:
- PAGE_LIST_READ
- PAGE_DETAIL_READ
x-enum-descriptions:
- Пользователю доступен табличный список с информационными страницами
- Пользователю доступна детальная страница информационной страницы

Этот же enum необходимо будет продублировать в admin-gui-backend в units_admin_user_role_rights_access_enum.yaml.

Затем в справочнике RightsAccess:

  1. Создать константу с названием раздела, в контексте которого будут выдаваться права.
  2. Добавить метод возвращающий массив новых прав доступа.
  3. В методе all() добавить в результирующий массив новый раздел и его права доступа по аналогии:
    public static function all(): array
{
return [
['section' => self::PAGES, 'items' => self::pages()],
];
}

public static function pages(): array
{
return [
new static(
RightsAccessEnum::PAGE_LIST_READ,
'Пользователю доступен табличный список с информационными страницами'
),
];
}

На этом этапе, после генерации клиента сервиса units/admin-auth права считаются добавленными, но еще никак не используются. Чтобы была возможность их использовать, т.е ограничивать доступ к методам, необходимо прописать политики прав доступа в admin-gui-backend.

Использование прав доступа

  1. Создать новую политику {controller_name}Policy.php для контроллера, методы которого необходимо ограничить:
├── Orders
│   ├── Controllers
│   │   ├── BasketsCommon
│   │   ├── OmsCommon
│   │   ├── Orders
│   │   └── Refunds
│   │   └── RefundsController.php
│   ├── Policies
│   │   ├── BasketsCommon
│   │   ├── OmsCommon
│   │   ├── Orders
│   │   └── Refunds
│   │   └── RefundsControllerPolicy.php
│   ├── Queries
│   ├── Requests
│   ├── Resources
│   └── Tests
  1. В политике объявить метод с названием анологичным закрываемому методу контроллера, который будет возвращать объект Illuminate\Auth\Access\Response.
  2. Проверить через кастомные методы модели пользователя allowOneOf() или allowAllOf() наличие необходимых прав:
use App\Domain\Auth\Models\User;
use Ensi\AdminAuthClient\Dto\RightsAccessEnum;
use Illuminate\Auth\Access\HandlesAuthorization;
use Illuminate\Auth\Access\Response;

class RefundsControllerPolicy
{
use HandlesAuthorization;

public function create(User $user): Response
{
return $user->allowOneOf([
RightsAccessEnum::ORDER_DETAIL_REFUND_CREATE,
]);
}
}
  • allowOneOf() - если пользователю достаточно иметь хотя бы одно право из переданного набора
  • allowAllOf() - если пользователю необходимо иметь все права из переданного набора

Выдача прав доступа

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