Страница 1 из 1

Статусы и rbac

Добавлено: 2019.09.16, 11:49
Chelobaka
Здравствуйте,

Есть модель у которой 10 разных статусов. Допустип Page.
Есть 3 группы пользователей, админ, редактор, копирайтер.

Как сделать так что бы Админ мог изменить статью на любой из 10 статусов.
Редактор на 5 из 10 статусов.
Копирайтер на 2 из 10 статусов.

В данный момент я использую такую конструкцию:

Код: Выделить всё


public static function getStatuses(int $user_role = User::CLIENT)
    {
        switch ($user_role) {
            case User::ADMIN:
                return [
                    Page::STATUS_NEW => Yii::t('page', 'New'),
                    ... другие 9 статусов ...
                ];
            case  User::EDITOR:
                return [
                   Page::STATUS_NEW => Yii::t('page', 'New'),
                    ... другие 4 статуса ...
                    ];

                break;
            case  User::COPYRIGHTER:
                return [
                    Page::STATUS_NEW => Yii::t('page', 'New'),
                    Page::STATUS_CANCEL => Yii::t('page', 'Cancel'),
                ];
                break;
        }
    }
    

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

Код: Выделить всё

 $statuses = Page::getStatuses(Yii::$app->user->identity->role);
При обновлении записи вызываю тот же метод ипроверяю есть ли статус в списке пришедших статусов.

Код: Выделить всё

 
 
 $statuses = Page::getStatuses(Yii::$app->user->identity->role);
 
 if (!in_array($status, $package_statuses)) {
            return false;
        }
 

Проблема в том что статусы могут добавиться, роли могут добавить и возможно есть давно готовое решение (паттерн) для таких случаев.

Re: Статусы и rbac

Добавлено: 2019.10.03, 05:18
BrusSENS
Набросал на коленке, надеюсь будет понятно.

Создаём таблицу для статусов с нужными Вам полями (в моём примере поля code - код статуса, name - его название) и полем allowed_to, в котором указываем роль, которой разрешено трогать данный статус.
Соответственно RBAC у нас может наследовать роли и разрешения.
Administarator например имеет доступ ко всему, к чему имеет доступ Moderator.
Таким образом добавив в allowed_to moderator мы разрешим использовать данный статус модератору и администратору. Если укажем administrator, то только администратор будет иметь доступ к данному статусу.

Код: Выделить всё

public function getAllowableStatusesList()
{
    // Выбираем все статусы
    $statuses = Status::find()->all();
    // Фильтруем статусы на доступ по полю allowed_to проверяя доступ
    $filtered =  array_filter($statuses, function ($status) {
    	return Yii::$app->user->can($status->allowed_to);
    });
   // Возвращаем статусы в массиве для дальшейшего скармливания в select
   return ArrayHelper::map($filtered, 'code', 'name');
}
свойство allowed_to по сути можем в бд сделать внешним ключом на auth_item.name.

В правилах валидации достаточно прописать

Код: Выделить всё

['allowed_to', 'in', 'range' => array_keys($this->getAllowableStatusesList()), 'allowArray' => false],

Re: Статусы и rbac

Добавлено: 2019.10.03, 17:39
yiiliveext
BrusSENS писал(а): 2019.10.03, 05:18 Набросал на коленке, надеюсь будет понятно.

Создаём таблицу для статусов с нужными Вам полями (в моём примере поля code - код статуса, name - его название) и полем allowed_to, в котором указываем роль, которой разрешено трогать данный статус.
Соответственно RBAC у нас может наследовать роли и разрешения.
Administarator например имеет доступ ко всему, к чему имеет доступ Moderator.
Таким образом добавив в allowed_to moderator мы разрешим использовать данный статус модератору и администратору. Если укажем administrator, то только администратор будет иметь доступ к данному статусу.
Это будет работать только с линейной иерархией.
Допустим у нас есть роли Пользователь1, Пользователь2, Пользователь3.
Роль Пользователь1 может использовать Статус1 и Статус2.
Роль Пользователь2 может использовать Статус2 и Статус3.
Роль Пользователь3 может использовать Статус3 и Статус4.
И какую роль вы пропишете в allowed_to для Статус2 и Статус3 в таком случае.

Re: Статусы и rbac

Добавлено: 2019.10.03, 20:40
BrusSENS
yiiliveext писал(а): 2019.10.03, 17:39 Это будет работать только с линейной иерархией.
Допустим у нас есть роли Пользователь1, Пользователь2, Пользователь3.
Роль Пользователь1 может использовать Статус1 и Статус2.
Роль Пользователь2 может использовать Статус2 и Статус3.
Роль Пользователь3 может использовать Статус3 и Статус4.
И какую роль вы пропишете в allowed_to для Статус2 и Статус3 в таком случае.
Что мешает сделать промежуточную таблицу? Или мне может расширение для ТСа написать на все случаи жизни?

Re: Статусы и rbac

Добавлено: 2019.10.04, 09:21
yiiliveext
BrusSENS писал(а): 2019.10.03, 20:40 Что мешает сделать промежуточную таблицу? Или мне может расширение для ТСа написать на все случаи жизни?
Там можно, конечно, но это все дурно пахнет. У нас уже есть в проекте RBAC Manager, который предоставляет исчерпывающий единый функционал для управлением ролями и разрешениями приложения. А вы хотите локально прикрутить к справочнику статусов второй недоменеджер. А если таких сущностей со статусами будет десяток или сотня? Прикрутите к каждому? Я хотел бы посмотреть, как вы будете это поддерживать и этим управлять :D

Re: Статусы и rbac

Добавлено: 2019.10.04, 13:50
yiijeka
rbac тут не причём.

1. Создаём getStatusesForUser($user) : iterable - используем при показе списка статусов
2. Создаём canUserUseStatus(User $user, Status $status) : bool - используем при проверках
Проблема в том что статусы могут добавиться, роли могут добавить и возможно есть давно готовое решение (паттерн) для таких случаев.
Если это изменится, то вам нужно будет всего то изменить тело метода getStatusesForUser.

Re: Статусы и rbac

Добавлено: 2019.10.04, 16:05
Chelobaka
yiijeka писал(а): 2019.10.04, 13:50 rbac тут не причём.

1. Создаём getStatusesForUser($user) : iterable - используем при показе списка статусов
2. Создаём canUserUseStatus(User $user, Status $status) : bool - используем при проверках
Проблема в том что статусы могут добавиться, роли могут добавить и возможно есть давно готовое решение (паттерн) для таких случаев.
Если это изменится, то вам нужно будет всего то изменить тело метода getStatusesForUser.
Как то так и делаю, но в принципе меня не устраивает switch использование которого подразумевается. Это противоречит концепции SOLID, а именно для расширения возможностей нужно менять класс, а не добавлять новый код.

Я думал создавать обьекты из преданных ролей пользователя которые будут содержать все эти методы. GetStatuses и т.д. Так при расширении ролей нужно будет добавить только новый класс ну и конечно если добавится статус до придется все классы переделывать, тоже не вариант.

Поэтому скорее всего правильно делать статусы как записи например ProductStatuses, и класс связи RoleProductRelation. Так в итоге будет все равно что там в классе, создавать объект из роли и будет возвращать все статусы без изменения классов.

Но как заметили выше, а что если сущностей 100 и статусов столько же. При добавлении сущности с статусами нужно переписывать класс связей. А если он еще и от какой то фабрики, то все подобные классы.

Re: Статусы и rbac

Добавлено: 2019.10.04, 16:08
Chelobaka
yiiliveext писал(а): 2019.10.04, 09:21
BrusSENS писал(а): 2019.10.03, 20:40 Что мешает сделать промежуточную таблицу? Или мне может расширение для ТСа написать на все случаи жизни?
Там можно, конечно, но это все дурно пахнет. У нас уже есть в проекте RBAC Manager, который предоставляет исчерпывающий единый функционал для управлением ролями и разрешениями приложения. А вы хотите локально прикрутить к справочнику статусов второй недоменеджер. А если таких сущностей со статусами будет десяток или сотня? Прикрутите к каждому? Я хотел бы посмотреть, как вы будете это поддерживать и этим управлять :D
Отличное замечание. Каждая новая сущность это будет ужас((

Re: Статусы и rbac

Добавлено: 2019.10.04, 16:35
yiijeka
> Это противоречит концепции SOLID, а именно для расширения возможностей нужно менять класс, а не добавлять новый код.
> Каждая новая сущность это будет ужас

Ну появится у вас новый статус. Создадите вы его. Никто этот статус не сможет использовать на сайте, пока вы в методе getStatusesForUser не добавите новый статус нужной роли пользователя. Никакого изменения кода нет, весь прежний функционал работает как работал.

Re: Статусы и rbac

Добавлено: 2019.10.04, 22:02
yiiliveext
yiijeka писал(а): 2019.10.04, 16:35 > Это противоречит концепции SOLID, а именно для расширения возможностей нужно менять класс, а не добавлять новый код.
> Каждая новая сущность это будет ужас

Ну появится у вас новый статус. Создадите вы его. Никто этот статус не сможет использовать на сайте, пока вы в методе getStatusesForUser не добавите новый статус нужной роли пользователя. Никакого изменения кода нет, весь прежний функционал работает как работал.
Хардкодить роли - зло, а так как тс делает, тем более. Но для мелких проектов прокатит.

Re: Статусы и rbac

Добавлено: 2019.10.16, 03:12
BrusSENS
yiiliveext писал(а): 2019.10.04, 09:21 Там можно, конечно, но это все дурно пахнет. У нас уже есть в проекте RBAC Manager, который предоставляет исчерпывающий единый функционал для управлением ролями и разрешениями приложения. А вы хотите локально прикрутить к справочнику статусов второй недоменеджер. А если таких сущностей со статусами будет десяток или сотня? Прикрутите к каждому? Я хотел бы посмотреть, как вы будете это поддерживать и этим управлять :D
Жаль времени не было зайти почитать этот бред. Какой недоменеджер? Чего там поддерживать? Вариант с промежуточной таблицей использую уже несколько лет для ограничения доступа к статусам материалов. Один раз написал и ничего поддерживать не нужно. При создании статуса могу сразу указать ограничения для ролей или пермишнов. Есть функционал массового присвоения ролей и пермишнов к статусам. Писать там час от силы такой менеджер. Сам RBAC у нас иметь ограничения для справочников не должен, как и знать о самих справочниках. Есть вариант сделать правилом, которое получает данные из БД, но суть от этого не поменяется.
Про упоминание ТСом SOLID вообще чуть не офонарел. Про какую сущность он говорит? Мне не понятно. 2 поля с PK по ним, всё. Внешний ключ для целостности. С ума уже смотрю все посходили с SOLID и подобными штуками... Не можем придумать, как простейший менеджер реализовать, зато о "высоком" думаем.