Как разруливать права доступа в зависимости от роли пользователя?

Привет.

Начну с простого примера, чтобы проще было сформулировать вопросы.

Итак, есть сущность Контракт с полями:
- number
- date
- manager_id


manager_id - привязка к пользователю, за которым закреплен контракт.

Есть роли (группы) пользователей:

- Директор (видит все контракты)
- Менеджер (видит только "свои" контракты)


Очевидно, что при выборке контрактов необходимо получить роль текущего пользователя, и в зависимости от нее выбрать нужные контракты. Однако в различных best practicies говорится о том, что в коде нужно работать с разрешениями, а не с ролями пользователя. В таком случае можно завести следующие разрешения:
- доступ ко всем контрактам (назначить это разрешение для роли "Директор")
- доступ к "своим" контрактам (назначить это разрешение для роли "Менеджер")


Тогда кажется, что все неплохо и в коде будет что-то типа:
if (User::hasPermission('all_contracts')) {
    Contract::all();
} elseif (User::hasPermission('own_contracts')) {
    Contract::getByManager(User::getId());
}


Предположим теперь, что у нас в системе появляется некий "Региональный директор", который должен видеть контракты в своем регионе. Видимо, в этом случае к контракту будет добавлено поле
- region_id
по которому будет осуществляться выборка для регионального директора.

Как в таком случае изменится код?
if (User::hasPermission('all_contracts')) {
    Contract::all();
} elseif (User::hasPermission('own_contracts')) {
    if (User::hasRole('manager')) {
        Contract::getByManager($managerId);
    } elseif (User::hasRole('region_manager')) {
        Contract::getByRegion(User::getRegionId());
    }
}

Так или иначе в коде появляется проверка ролей пользователя.

Правильно ли это? Если нет - то как реализуете вы?

И вопрос вдогонку, уже конкретно о Laravel: правильно ли я понимаю, что данное разруливание прав необходимо выносить в сервис-провайдер? Вроде бы контроллеры/модели/репозитории для таких вещей не предназначены.
  • Вопрос задан
  • 3173 просмотра
Решения вопроса 1
Astatroth
@Astatroth
Я тут случайно
Чтобы не городить кучу методов для выборки на каждый случай жизни, я бы сделал скоуп, который принимал бы пользователя в качестве аргумента и фильтровал записи в зависимости от пермишенов. Тогда выборка контрактов всегда будет "чистой", типа
Contract::withPermission($user)->get();

В скоупе уже придется прописать фильтры по пермишенам.
Да, может это и не бест практис, но ведь работает. Теоретически, конечно, такого не приходилось реализовывать еще.
Ответ написан
Пригласить эксперта
Ответы на вопрос 4
andreybold
@andreybold
Я бы посоветовал вам использовать готовые пакеты для таких целей. Тогда у вас будет возможность и проверки прав в методах контроллера, и получении моделей отвечающих тем правам, которые вы укажите (через скоупы)
Ответ написан
Комментировать
kylt_lichnosti
@kylt_lichnosti
Вам должны помочь вотеры - https://symfony.com/doc/current/security/voters.html
Ответ написан
Комментировать
e_svirsky
@e_svirsky
Web Developer
Symfony ACL
Ответ написан
Комментировать
dlnsk
@dlnsk
ПК Партнер 01.01 -> ПК Поиск -> IBM PC
Вот моя статья как раз на эту тему: Laravel 5. Иерархический RBAC для самых маленьких
Пакет, о котором идет речь позволяет вообще не менять код самого приложения при добавлении новых ролей, создавать и изменять роли очень гибко и использовать стандартные возможности Laravel, в том числе, и в шаблонах.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы