Права пользователей в зависимости от сущности.

Всё про контроль доступа пользователей: фильтры, RBAC, проверки
Ответить
buba
Сообщения: 24
Зарегистрирован: 2017.01.05, 13:42

Права пользователей в зависимости от сущности.

Сообщение buba » 2019.01.04, 23:02

Не могу придумать как правильно использовать RBAC для такой ситуации (и нужно ли его вообще здесь использовать).

Приведу пример работы.
Сервис делится на два условных "Кабинета" - для Покупателей и для Продавцов (Директора и Сотрудников компании).

Имеется база "Компании", с компаниями связаны разнообразные сущности - "Категории", "Товары" и пр.

У каждой компании есть Директор (имеет доступ в интерфейс для Продавцов и может управлять всей компанией - редактировать товары, категории и пр.), Сотрудником ( имеет доступ в интерфейс для Продавцов и может делать только то, что было разрешено Директором). Доступ к данным Компаний могут иметь только Покупатели, которым Директор или Сотрудник дали доступ.
При этом один и тот же пользователь может быть у разных компаний в разных ролях (у одной Директором, у другой Сотрудником, у третьей Покупателем), и даже в одной и той же Компании у пользователя могут быть роли Директора/Сотрудника и Покупателя одновременно.

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

Все пользователи хранятся в общей таблице users и связываются с компаниями через промежуточную таблицу users2company.

Как лучше организовать права при такой схеме?

Аватара пользователя
ElisDN
Сообщения: 5419
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Права пользователей в зависимости от сущности.

Сообщение ElisDN » 2019.01.05, 10:49

Спрограммируйте свои Rule со всей этой логикой.

buba
Сообщения: 24
Зарегистрирован: 2017.01.05, 13:42

Re: Права пользователей в зависимости от сущности.

Сообщение buba » 2019.01.05, 18:24

Не понимаю, с чего начинать.

buba
Сообщения: 24
Зарегистрирован: 2017.01.05, 13:42

Re: Права пользователей в зависимости от сущности.

Сообщение buba » 2019.01.05, 18:48

ElisDN писал(а):
2019.01.05, 10:49
Спрограммируйте свои Rule со всей этой логикой.
Ну или я пока понимаю вот такую схему, поправьте, если что не так.
Берем мануал и видим, что мы можем наклепать своих правил правил и рулить ими в зависимости от своих пожеланий. Значит делаем:

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

namespace app\rbac;

use yii\rbac\Rule;
class DirectorRule extends Rule
{
    public $name = 'isDirector';

    /**
     * @param string|int $user the user ID.
     * @param Item $item the role or permission that this rule is associated width.
     * @param array $params parameters passed to ManagerInterface::checkAccess().
     * @return bool a value indicating whether the rule permits the role or permission it is associated with.
     */
    public function execute($user, $item, $params)
    {
        return isset($params['company']) ? $params['company']->users2company->user_id == $user : false;
    }
}
Далее делаем контроллер, который создает нам нужные роли, что-то типа:

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

namespace app\commands;

use Yii;
use yii\console\Controller;

class RbacController extends Controller
{
    public function actionInit()
    {
        $auth = Yii::$app->authManager;        

// add the rule
$rule = new \app\rbac\DirectorRule;
$auth->add($rule);

// добавляем разрешение "updateOwnPost" и привязываем к нему правило.
$updateAllInCompany= $auth->createPermission('updateAllInCompany');
$updateAllInCompany->description = 'Update all data in the Company';
$updateAllInCompany->ruleName = $rule->name;
$auth->add($updateAllInCompany);          
        

        // добавляем роль "director" и даём роли разрешение "updateAllInCompany"
        $director = $auth->createRole('director');
        $auth->add($director );
        $auth->addChild($director , $updateAllInCompany);
        

        // Назначение ролей пользователям. 1 и 2 это IDs возвращаемые IdentityInterface::getId()
        // обычно реализуемый в модели User.
        $auth->assign($director , 2);
    }
}
Ну и дальше в своих контроллерах использую проверку:

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

if (\Yii::$app->user->can('updateAllInCompany', ['company' => $company])) {
    // update company
}

Правильно?
Последний раз редактировалось buba 2019.01.05, 18:53, всего редактировалось 1 раз.

buba
Сообщения: 24
Зарегистрирован: 2017.01.05, 13:42

Re: Права пользователей в зависимости от сущности.

Сообщение buba » 2019.01.05, 18:52

А ведь получается, что аналогичным образом я могу использовать matchCallback, но тогда будет куча дублирующего кода.

Или подход с matchCallback тут не подходит?

Аватара пользователя
ElisDN
Сообщения: 5419
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Права пользователей в зависимости от сущности.

Сообщение ElisDN » 2019.01.05, 19:56

Правильно. А matchCallback работает только в AccessControl.

buba
Сообщения: 24
Зарегистрирован: 2017.01.05, 13:42

Re: Права пользователей в зависимости от сущности.

Сообщение buba » 2019.01.05, 20:42

А как лучше организовать функционал, чтобы Директор мог Сотрудникам назначать свои права? Забивать все возможные варианты в RBAC или городить свою систему проверки прав?

Аватара пользователя
ElisDN
Сообщения: 5419
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Права пользователей в зависимости от сущности.

Сообщение ElisDN » 2019.01.06, 10:38

Проще свою систему. И закинуть её внутрь Rule.

buba
Сообщения: 24
Зарегистрирован: 2017.01.05, 13:42

Re: Права пользователей в зависимости от сущности.

Сообщение buba » 2019.01.06, 11:12

ElisDN писал(а):
2019.01.06, 10:38
Проще свою систему. И закинуть её внутрь Rule.
Т.е. по принципу как выше?

Типа такого?

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

namespace app\rbac;

use yii\rbac\Rule;
class SotrudnikRule extends Rule
{
    public $name = 'SotrudnikRules';

    /**
     * @param string|int $user the user ID.
     * @param Item $item the role or permission that this rule is associated width.
     * @param array $params parameters passed to ManagerInterface::checkAccess().
     * @return bool a value indicating whether the rule permits the role or permission it is associated with.
     */
    public function execute($user, $item, $params)
    {
        //здесь адов код по проверке прав у конкретного юзера
    }
}

buba
Сообщения: 24
Зарегистрирован: 2017.01.05, 13:42

Re: Права пользователей в зависимости от сущности.

Сообщение buba » 2019.01.06, 17:23

Всё вникаю в RBAC и начинает казаться, что описанный, мной выше, подход не очень удобный. Получается, что у меня динамические правила (которые включаются/выключаются в зависимости от статуса пользователя, т.е. фактически роли пользователя), а правильнее было бы динамически назначать роль пользователю. Но что-то не могу найти вариантов решений как динамически назначить роль пользователю.

Аватара пользователя
ElisDN
Сообщения: 5419
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Права пользователей в зависимости от сущности.

Сообщение ElisDN » 2019.01.06, 23:33

Не зацикливайтесь на ролях фреймворка. Не делайте в RbacController ролей директора и прочих. Сделайте для всех одну статическую фреймворковскую роль user и спрограммируйте всю свою логику в разных Permission к ней.

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

class EditOwnCompanyRule extends Rule
{
    public fubction execute($user, $item, $params)
    {
        $company = $params['company'];
        
        return $company->canBeEditedByUser($user->id);
    }
}

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

if (Yii::$app->user->can('edit-company', $company) ...

buba
Сообщения: 24
Зарегистрирован: 2017.01.05, 13:42

Re: Права пользователей в зависимости от сущности.

Сообщение buba » 2019.01.07, 12:41

Но почему, в чём выгода?
Удобней же сделать сразу роли, вроде и "идеологически" правильней всю работу на фреймворк свалить ну и управлять проще - сделал админку и рули права.

Аватара пользователя
maleks
Сообщения: 1769
Зарегистрирован: 2012.12.26, 12:56

Re: Права пользователей в зависимости от сущности.

Сообщение maleks » 2019.01.07, 13:43

buba писал(а):
2019.01.06, 17:23
Но что-то не могу найти вариантов решений как динамически назначить роль пользователю.
А вы выше назначали же - $auth->assign($director , 2); - вот так и назначать

buba
Сообщения: 24
Зарегистрирован: 2017.01.05, 13:42

Re: Права пользователей в зависимости от сущности.

Сообщение buba » 2019.01.07, 14:24

maleks писал(а):
2019.01.07, 13:43
buba писал(а):
2019.01.06, 17:23
Но что-то не могу найти вариантов решений как динамически назначить роль пользователю.
А вы выше назначали же - $auth->assign($director , 2); - вот так и назначать
Не, это статически получается. А мне надо динамически, чтобы если человек хочет получить доступ к данной Компании-1 у него одна роль, а для Компании-2 другая роль.

Вроде нашёл подходящее решение - https://www.yiiframework.com/doc/guide/ ... -umolcaniu , но смущает то, что в методе execute надо, фактически, написать всю иерархию имеющихся ролей
Обратите внимание, так как "author" добавлен как дочерняя роль к "admin", следовательно в реализации метода execute() класса правила вы должны учитывать эту иерархию. Именно поэтому для роли "author" метод execute() вернёт истину, если пользователь принадлежит к группам 1 или 2 (это означает, что пользователь находится в группе администраторов или авторов)
Но зачем мы тогда указываем иерархию при создании этих ролей? У нас и так author идёт потомком от admin, но в методе execute мы это опять перепроверяем, а если у нас 10 ролей, то и 10 проверок. :?

Аватара пользователя
ElisDN
Сообщения: 5419
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Права пользователей в зависимости от сущности.

Сообщение ElisDN » 2019.01.07, 15:09

buba писал(а):
2019.01.07, 12:41
Но почему, в чём выгода?
Удобней же сделать сразу роли, вроде и "идеологически" правильней всю работу на фреймворк свалить ну и управлять проще - сделал админку и рули права.
Потому, что фреймворк умеет только assign($director, $user) статически, а вам нужно сделать assign($director, $user, $company) динамически.

buba
Сообщения: 24
Зарегистрирован: 2017.01.05, 13:42

Re: Права пользователей в зависимости от сущности.

Сообщение buba » 2019.01.07, 15:27

ElisDN писал(а):
2019.01.07, 15:09
buba писал(а):
2019.01.07, 12:41
Но почему, в чём выгода?
Удобней же сделать сразу роли, вроде и "идеологически" правильней всю работу на фреймворк свалить ну и управлять проще - сделал админку и рули права.
Потому, что фреймворк умеет только assign($director, $user) статически, а вам нужно сделать assign($director, $user, $company) динамически.
Ну если фреймоврк что-то куда-то записал, значит и прочитать может. Разве переопределить метод "чтения" роли не вариант?

Аватара пользователя
maleks
Сообщения: 1769
Зарегистрирован: 2012.12.26, 12:56

Re: Права пользователей в зависимости от сущности.

Сообщение maleks » 2019.01.07, 15:46

buba писал(а):
2019.01.07, 14:24
Не, это статически получается.
Статически - это когда вы в миграции или консольном скрипте перестраиваете всю систему прав.
Но тот же assign вы можете и в админке делать.
Например на странице создания/редактирования профиля пользователя галками указывать его роли.

buba
Сообщения: 24
Зарегистрирован: 2017.01.05, 13:42

Re: Права пользователей в зависимости от сущности.

Сообщение buba » 2019.01.07, 15:48

maleks писал(а):
2019.01.07, 15:46
buba писал(а):
2019.01.07, 14:24
Не, это статически получается.
Статически - это когда вы в миграции или консольном скрипте перестраиваете всю систему прав.
Но тот же assign вы можете и в админке делать.
Например на странице создания/редактирования профиля пользователя галками указывать его роли.
В том-то и дело, что в админке это сохраняется пока я (админ) не поменяю. А роли у пользователя должны меняться в зависимости от запрошенного контроллера и/или экшена.

Т.е. на странице
/company/1/index пользователь Директор, а на странице /company/2/index он уже Покупатель.

Аватара пользователя
maleks
Сообщения: 1769
Зарегистрирован: 2012.12.26, 12:56

Re: Права пользователей в зависимости от сущности.

Сообщение maleks » 2019.01.07, 15:59

buba писал(а):
2019.01.07, 15:48
В том-то и дело, что в админке это сохраняется пока я (админ) не поменяю. А роли у пользователя должны меняться в зависимости от запрошенного контроллера и/или экшена.
Вы путаете ваши роли, как текущий выбор пользователя, и роли в понятиях RBAC, как то что он в принципе сможет вообще делать.
buba писал(а):
2019.01.07, 15:48
Т.е. на странице
/company/1/index пользователь Директор, а на странице /company/2/index он уже Покупатель.
Он будет Директором на странице /company/1/index если ,например, одна из ролей, которая ему присвоена, владеет разрешением director_access_to_company_id

buba
Сообщения: 24
Зарегистрирован: 2017.01.05, 13:42

Re: Права пользователей в зависимости от сущности.

Сообщение buba » 2019.01.07, 16:21

maleks писал(а):
2019.01.07, 15:59
buba писал(а):
2019.01.07, 15:48
В том-то и дело, что в админке это сохраняется пока я (админ) не поменяю. А роли у пользователя должны меняться в зависимости от запрошенного контроллера и/или экшена.
Вы путаете ваши роли, как текущий выбор пользователя, и роли в понятиях RBAC, как то что он в принципе сможет вообще делать.
buba писал(а):
2019.01.07, 15:48
Т.е. на странице
/company/1/index пользователь Директор, а на странице /company/2/index он уже Покупатель.
Он будет Директором на странице /company/1/index если ,например, одна из ролей, которая ему присвоена, владеет разрешением director_access_to_company_id
Ну да, только с таким подходом смысла в ролях нет. Всё можно будет разруливать через разрешения. А это, кмк, не очень удобное решение, т.к. придется для каждого "типа" пользователя городить свои конструкции с разрешенными действиями.

Мне кажется, правильнее было бы отталкиваться от стандартного RBAC'а, с его разрешениями и иерархией. Тогда проще добавлять новые роли (если понадобятся) и новые разрешения. И будет всего один чёрный ящик - динамическое назначение роли пользователя.

Ответить