Еще вопрос по RBAC

Всё про контроль доступа пользователей: фильтры, RBAC, проверки
Ответить
Аватара пользователя
Neuromance
Сообщения: 716
Зарегистрирован: 2011.09.06, 13:04

Еще вопрос по RBAC

Сообщение Neuromance »

Всем привет.
Вот имеется таблица order_service, в которой среди прочих есть колонка manager_id.
И есть таблица service, в которой есть колонка owner_id.

Имеются 2 пермишшна BProviderTicketViewForManager и BProviderTicketView(BProviderTicketViewForManager родитель для BProviderTicketView)
Первый проверяет доступ к просмотру страницы, определяя, является ли пользователь менеджером услуги заказа(совпадает ли поле manager_id таблицы order_service с текущим пользователем). А второй проверяет доступ на просмотр для роли Provider и роли Provider_manager(всех менеджеров этого конкретного провайдера).
Соответственно на каждом висит соответствующее правило.

И вот так выглядят эти правила

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

class ProviderAccessRule extends Rule
{

    /**
     * @inheritdoc
     */
    public $name = 'providerAccess';

    /**
     * @inheritdoc
     */
    public function execute($user, $item, $params)
    {
        if(isset($params['model'])){
            /** @var Provider $model */
            $model = $params['model'];

            $userModel = User::findByPk($user);

            if(isset($model->owner_id))
                return $model->owner_id == $userModel->getMainId();
            else return true;
        }
        return false;
    }
}

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

class ManagerAccessRule extends Rule
{

    /**
     * @inheritdoc
     */
    public $name = 'managerAccess';

    /**
     * @inheritdoc
     */
    public function execute($user, $item, $params)
    {
        if(isset($params['model'])){
            /** @var Provider $model */
            $model = $params['model'];

            if(isset($model->manager_id))
                return $model->manager_id == $user;
        }
        return false;
    }
}
И вот в 2 этих правилах проверяются 2 разные модели (Service и OrderService).
А проверку доступа мне надо будет делать на один дочерний пермишшн - Yii->$app->getUser()->can('BProviderTicketView', [...])

Соответственно встал вопрос как лучше быть. То ли делать 2 разные проверки. То ли в правилах всё сводить к одной модели(но это не хотелось бы делать, т.к. правила могут и в других местах быть использованы)..То ли что-то еще придумывать.
godzie
Сообщения: 62
Зарегистрирован: 2016.04.03, 00:38

Re: Еще вопрос по RBAC

Сообщение godzie »

Использовал бы 2й вариант, но сделал бы правило производное из ваших 2х

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

class Rule3 extends Rule{
    ...
    public function execute($user, $item, $params)
    {    
    if (
        $rule1->execute($user, $item, ['model' => $params['model1']])
        &&
        $rule2->execute($user, $item, ['model' => $params['model2']])
        ) {
            return true;
        } else {
            return false;
        }
                
    }
    
}

 
$rule1 и $rule2 можете подтянуть из вашего authManager'a
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: Еще вопрос по RBAC

Сообщение samdark »

Я бы перекроил URL-ы на user/10/ticket/42 и давал бы 404, если owner не совпадает прямо в контроллере без RBAC:

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

public function actionView($userId, $id)
{
    $ticket = Ticket::findOne(['id' => $id, 'created_by' => $userId]);
    if ($ticket) {
        // 404
    }
}
 
Аватара пользователя
Йож
Сообщения: 574
Зарегистрирован: 2015.08.26, 03:05

Re: Еще вопрос по RBAC

Сообщение Йож »

И еще не забыть проверить юзера текущего и который указан в URL :)
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: Еще вопрос по RBAC

Сообщение samdark »

Ну да.
Аватара пользователя
Neuromance
Сообщения: 716
Зарегистрирован: 2011.09.06, 13:04

Re: Еще вопрос по RBAC

Сообщение Neuromance »

Спасибо за ответы.. Решил нарисовать схему привязки ролей к пермишшнам и связку их с правилами..
Объединение 2 правил в одно не подошло, т.к. нужны были пермишшны как с отдельными этими правилами, так и с объединенными.
В итоге нарисовал 2 такие ветки.
role_provider_manager -> BProviderTicketViewForManager (rule = managerRule) -> BProviderTicketViewForProvider( rule = providerRule) -> BProviderTicketView

role_provider -> BProviderTicketViewForProvider( rule = providerRule) -> BProviderTicketView

В каждом правиле немного похардкодил (решил, что это в данном контексте допустимо).

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

class ManagerAccessRule extends Rule
{

    /**
     * @inheritdoc
     */
    public $name = 'managerAccess';

    /**
     * @inheritdoc
     */
    public function execute($user, $item, $params)
    {
        if(isset($params['model'])) {
            /** @var Provider $model */
            $model = $params['model'];
        }
        elseif(isset($params['orderServiceModel'])){
            $model = $params['orderServiceModel'];
        }
        else return false;

        if(isset($model->manager_id) || $model->hasAttribute('manager_id')) {
            return $model->manager_id == $user;
        }
        else return true;
    }

}

class ProviderAccessRule extends Rule
{

    /**
     * @inheritdoc
     */
    public $name = 'providerAccess';

    /**
     * @inheritdoc
     */
    public function execute($user, $item, $params)
    {
        if(isset($params['model'])) {
            /** @var Provider $model */
            $model = $params['model'];
        }
        elseif(isset($params['serviceModel'])){
            $model = $params['serviceModel'];
        }
        else return false;

        $userModel = User::findByPk($user);

        if(isset($model->owner_id) || $model->hasAttribute('owner_id')){
            return $model->owner_id == $userModel->getMainId();
        }
        else return true;
    }

}
И проверку стал делать так

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

$access = \Yii::$app->user->can('BOrderServiceAccept', [
        'orderServiceModel' => $model,
        'serviceModel' => $model->service,
]);
Ответить