Динамическая проверка прав на основе rbac\DbManager

Выкладываем свои наработки
Аватара пользователя
Roksalana
Сообщения: 215
Зарегистрирован: 2014.01.14, 09:34

Динамическая проверка прав на основе rbac\DbManager

Сообщение Roksalana »

По-моему самый частый вопрос на форуме - это настройка rbac. И это несмотря на огромное количество мануалов по его настройке на основе PhpManager. Предлагаю всем желающим модуль для работы с ролями и правами на основе DbManager - настройка прав доступа и ролей через веб-интерфейс.

Но модуль задумывался лишь как сопутствующий инструмент для поведения, которое на лету проверяет права доступа. Имхо - это очень удобно. В Yii2 легко создавать, устанавливать и использовать модули. Но "чужой" модуль не знает моих пользователей, мои роли и тп. Максимум что может внести автор чужого модуля - роль "admin" на все случаи жизни. А если я хочу более тонкую настройку прав? Переопределять все контроллеры модуля только ради прописывания прав? А завтра я еще их захочу менять. Имхо, авторы модулей не должны думать о проблемах доступа, это должно быть за пределом их компетенции. А доступы будет разруливать вот такое поведение.

Скачать модуль и поведение можно с гитхаба.
Я тестировала на своих проектах, буду признательна, если кто еще проверит работу на своем приложении.

Стоит ли добавить возможность прописывать бизнес-правила для роли или правила? Для их написания нужно понимать принципы rbac, а мне хочется чтобы использование модуля не требовало никаких доп.знаний. Подумываю над созданием универсальных бизнес-правил, например $user->getId() == $object->{$filed}

Буду рада любым замечаниям, пожеланиям, предложениям и пул-реквестам ;)
somelogin
Сообщения: 42
Зарегистрирован: 2015.03.11, 03:07

Re: Динамическая проверка прав на основе rbac\DbManager

Сообщение somelogin »

Очень удобный модуль. У меня правда не все получилось реализовать, но мне понравилась идея, так что в любом случае спасибо вам. Я новичок и пробовал разобрать весь ваш код по косточкам. Меня интересует вот этот кусок кода из поведения:

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

if(!$this->cheсkByRule($action, $user, $request))
        {
            //И по AuthManager
            if(!$this->checkPermission($route))
                throw new BadRequestHttpException('Не достаточно прав');
        } 
Вся моя база пустая (таблицы созданы, но я их не заполнял), а в конфиге я указал:

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

'as AccessBehavior' => [
        'class' => AccessBehavior::className(),
        'rules' =>
            ['site' =>
                [
                    [
                        'actions' => ['login', 'index'],
                        'allow' => true,
                    ],
                ]
            ]
    ] 
Я проверил, действительно, никуда не могу зайти, кроме как на site/login и site/index. Однако, если это дело проверять в режиме разработки и с панелью дебага(в продакшене эти ошибки опускаются и не выводятся на страницу), то когда я захожу на site/login или site/index, под футером у меня просто строкой пишется ошибка: "Bad Request (#400): Не достаточно прав"(на самом деле это писалось на любой странице, об этом чуть ниже). Т.е. он вроде как и дает доступ, и не дает. Тогда я подкорректировал немного код поведения для теста:

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

if(!$this->cheсkByRule($action, $user, $request))
        {
            //И по AuthManager
            if(!$this->checkPermission($route))
            {
                echo "TEST";
                throw new BadRequestHttpException('Не достаточно прав');
             }
        }
         
Оказалось, что куда бы я не заходил (даже на несуществующие страницы, которые выдают ошибку 404), у меня везде по футером теперь пишется: "TESTBad Request (#400): Не достаточно прав". Т.е. cheсkByRule(..) и checkPermission(..) всегда false (либо null, что не влияет). Логично, что проверка по AuthManager (я про checkPermission(..)) возвращает false, т.к. у меня пустая база данных, но если я захожу, к примеру, на site/index, то он при проверке по конфигу (cheсkByRule(..)) должен возвращать true и ничего не делать. Надеюсь, понятно объяснил свою проблему. Надеюсь на вашу помощь, ибо очень долго провозился с этим, но так ни к чему и не пришел.
Аватара пользователя
Roksalana
Сообщения: 215
Зарегистрирован: 2014.01.14, 09:34

Re: Динамическая проверка прав на основе rbac\DbManager

Сообщение Roksalana »

Спасибо за то, что решили воспользоваться моим модулем, мне очень приятно :)
Проблема в том, что у вас нет доступа к дебагеру. Он отдельным запросом подгружается. Нужно добавить в конфиг правила доступа к дебагеру
"/debug/default" как-то так:

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

'as AccessBehavior' => [
        'class' => AccessBehavior::className(),
        'rules' =>
            ['site' =>
                [
                    [
                        'actions' => ['login', 'index'],
                        'allow' => true,
                    ],
                ]
            ],
    ['debug' =>
                [
                    [
                        'allow' => true,
                    ],
                ]
            ]

    ] 
 
somelogin
Сообщения: 42
Зарегистрирован: 2015.03.11, 03:07

Re: Динамическая проверка прав на основе rbac\DbManager

Сообщение somelogin »

Спасибо, что так быстро ответили :)
Но проблема все равно не решилась. Если вставлять ваш код, то выдает ошибку:
"Setting unknown property: rbac\behaviors\AccessBehavior::0"
Это вроде как логично, т.к. мы вроде как 'rules' должны передавать один массив, который состоит из конфигурация, а не два через запятую. Поправил вот так:

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

'as AccessBehavior' => [
        'class' => AccessBehavior::className(),
        'rules' =>
            [
                'site' =>
                    [
                        [
                            'actions' => ['index'],
                            'allow' => true,
                        ],
                    ]
                'debug' =>
                    [
                        [
                            'allow' => true,
                        ],
                    ]
            ],
    ] 
Все заработало, но с той же проблемой.
Аватара пользователя
Insolita
Сообщения: 788
Зарегистрирован: 2011.06.06, 01:39
Контактная информация:

Re: Динамическая проверка прав на основе rbac\DbManager

Сообщение Insolita »

У меня правда другое поведение немного, но для дебаггера так стоит

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

[
  //..........
    [
        'controllers' => ['debug/default'],
        'actions' => [],
        'allow' => true,
    ],
      //..........
  ]
кстати удобно вынести массив _accessrules в отдельный файл c возвращаемым массивом, а в основной его require так же как params

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

 'as globalAccess'=>[
        'class'=>'\common\components\behaviors\GlobalAccessBehavior',
        'rules'=>require(__DIR__.'/_accessrules.php')
    ],
somelogin
Сообщения: 42
Зарегистрирован: 2015.03.11, 03:07

Re: Динамическая проверка прав на основе rbac\DbManager

Сообщение somelogin »

Insolita, спасибо за наводку. Данный код работает:

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

'as AccessBehavior' => [
        'class' => AccessBehavior::className(),
        'rules' =>
            [
                'site' =>
                    [
                        [
                            'actions' => ['index'],
                            'allow' => true,
                        ],
                    ],
                'debug/default' =>
                    [
                        [
                            'actions' => [],
                            'allow' => true,
                        ],
                    ]
            ],
    ] 
fire-bug
Сообщения: 2
Зарегистрирован: 2015.03.31, 10:48

Re: Динамическая проверка прав на основе rbac\DbManager

Сообщение fire-bug »

я новичек((
При попытке установки вылетает ошибка:
D:\OpenServer\domains\lk-ia>composer require developeruz/yii2-db-rbac «*»
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Your requirements could not be resolved to an installable set of packages.

Problem 1
— The requested package developeruz/yii2-db-rbac could not be found in any v
ersion, there may be a typo in the package name.

Potential causes:
— A typo in the package name
— The package is not available in a stable-enough version according to your min
imum-stability setting
see f
or more details.

Read for further common
problems.

Installation failed, reverting ./composer.json to its original content.


Что это может быть?? Помогите плиз)
Аватара пользователя
Roksalana
Сообщения: 215
Зарегистрирован: 2014.01.14, 09:34

Re: Динамическая проверка прав на основе rbac\DbManager

Сообщение Roksalana »

fire-bug писал(а):я новичек((
Installation failed, reverting ./composer.json to its original content.

Что это может быть?? Помогите плиз)
Попробуйте так:

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

D:\OpenServer\domains\lk-ia>composer require developeruz/yii2-db-rbac "dev-master"
 
fire-bug
Сообщения: 2
Зарегистрирован: 2015.03.31, 10:48

Re: Динамическая проверка прав на основе rbac\DbManager

Сообщение fire-bug »

уже так и сделал, но все равно спасибо))
Аватара пользователя
Roksalana
Сообщения: 215
Зарегистрирован: 2014.01.14, 09:34

Re: Динамическая проверка прав на основе rbac\DbManager

Сообщение Roksalana »

По многочисленным просьбам в модуль добавлена страница для привязки роли пользователю.
Спасибо всем, кто пользуется данным модулем :) Жду новых пожеланий и предложений.
Ekstazi
Сообщения: 1428
Зарегистрирован: 2009.08.20, 22:54
Откуда: Молдова, Бельцы
Контактная информация:

Re: Динамическая проверка прав на основе rbac\DbManager

Сообщение Ekstazi »

+1 к идее, разработка очень полезная.
polumerk
Сообщения: 80
Зарегистрирован: 2015.07.09, 16:04

Re: Динамическая проверка прав на основе rbac\DbManager

Сообщение polumerk »

мучаюсь вторую неделю((

У меня в конфиге бекенда добавлено следующее:

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

<?php

$params = array_merge(
    require(__DIR__ . '/../../common/config/params.php'),
    require(__DIR__ . '/../../common/config/params-local.php'),
    require(__DIR__ . '/params.php'),
    require(__DIR__ . '/params-local.php')
);


use developeruz\db_rbac\behaviors\AccessBehavior;

return [
    'id' => 'app-backend',
    'basePath' => dirname(__DIR__),
    'controllerNamespace' => 'backend\controllers',
    'bootstrap' => ['log'],    
    'as AccessBehavior' => [
        'class' => AccessBehavior::className(),
        'rules' =>
            ['site' =>
                [
                    [
                        'allow' => true,
                    ],
                ],
            'permit/access' =>
                [
                    [
                        'actions' => ['role',],
                        'allow' => true,
                    ],
                ],
            'debug/default' =>
                [
                    [
                        'allow' => true,
                    ],
                ], 
            ], 
                        
    ],
    'modules' => [
        'permit' => [
            'class' => 'developeruz\db_rbac\Yii2DbRbac',
           'params' => [
                'userClass' => 'common\models\User',
            ]
        ],
    ],
    'components' => [
        'user' => [
            'identityClass' => 'common\models\User',
            'enableAutoLogin' => true,
        ],
        'log' => [
            'traceLevel' => YII_DEBUG ? 3 : 0,
            'targets' => [
                [
                    'class' => 'yii\log\FileTarget',
                    'levels' => ['error', 'warning'],
                ],
            ],
        ],        
    'errorHandler' => [ 'errorAction' => 'site/error',    
    ],    

    ], 
    'params' => $params,

]; 
в контроллере куда захожу прописано:

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

    public function behaviors()
    {
        return [
            'verbs' => [
                'class' => VerbFilter::className(),
                'actions' => [
                    'delete' => ['post'],
                ],
            ],
            
        ];
    }


    public function action()
    {
        return [
                // declares "error" action using a class name
                'error' => 'yii\web\ErrorAction',

            ];
    }     
ни каких ролей не выдано на контроллер и я пытаясь зайти получаю вот такую ошибку:
An Error occurred while handling another error:
exception 'yii\web\BadRequestHttpException' with message 'Не достаточно прав' in W:\domains\fczb\vendor\developeruz\yii2-db-rbac\behaviors\AccessBehavior.php:50
Stack trace:
#0 [internal function]: developeruz\db_rbac\behaviors\AccessBehavior->interception(Object(yii\base\ActionEvent))
#1 W:\domains\fczb\vendor\yiisoft\yii2\base\Component.php(541): call_user_func(Array, Object(yii\base\ActionEvent))
#2 W:\domains\fczb\vendor\yiisoft\yii2\base\Module.php(607): yii\base\Component->trigger('beforeAction', Object(yii\base\ActionEvent))
#3 W:\domains\fczb\vendor\yiisoft\yii2\base\Controller.php(139): yii\base\Module->beforeAction(Object(yii\web\ErrorAction))
#4 W:\domains\fczb\vendor\yiisoft\yii2\base\Module.php(455): yii\base\Controller->runAction('error', Array)
#5 W:\domains\fczb\vendor\yiisoft\yii2\web\ErrorHandler.php(80): yii\base\Module->runAction('site/error')
#6 W:\domains\fczb\vendor\yiisoft\yii2\base\ErrorHandler.php(101): yii\web\ErrorHandler->renderException(Object(yii\web\BadRequestHttpException))
#7 [internal function]: yii\base\ErrorHandler->handleException(Object(yii\web\BadRequestHttpException))
#8 {main}
Previous exception:
exception 'yii\web\BadRequestHttpException' with message 'Не достаточно прав' in W:\domains\fczb\vendor\developeruz\yii2-db-rbac\behaviors\AccessBehavior.php:50
Stack trace:
#0 [internal function]: developeruz\db_rbac\behaviors\AccessBehavior->interception(Object(yii\base\ActionEvent))
#1 W:\domains\fczb\vendor\yiisoft\yii2\base\Component.php(541): call_user_func(Array, Object(yii\base\ActionEvent))
#2 W:\domains\fczb\vendor\yiisoft\yii2\base\Module.php(607): yii\base\Component->trigger('beforeAction', Object(yii\base\ActionEvent))
#3 W:\domains\fczb\vendor\yiisoft\yii2\base\Controller.php(139): yii\base\Module->beforeAction(Object(yii\base\InlineAction))
#4 W:\domains\fczb\vendor\yiisoft\yii2\base\Module.php(455): yii\base\Controller->runAction('permission', Array)
#5 W:\domains\fczb\vendor\yiisoft\yii2\web\Application.php(84): yii\base\Module->runAction('permit/access/p...', Array)
#6 W:\domains\fczb\vendor\yiisoft\yii2\base\Application.php(375): yii\web\Application->handleRequest(Object(yii\web\Request))
#7 W:\domains\fczb\backend\web\index.php(18): yii\base\Application->run()
#8 {main}
не знаю как это побороть, если убираю из конфига:\

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

      
    'errorHandler' => [ 'errorAction' => 'site/error',    
    ],    
то выводится отдельная страница с ошибкой из поставки yyi2, а не моя.

Где ошибка, в чем заключается такая проблема не могу понять((
Аватара пользователя
Roksalana
Сообщения: 215
Зарегистрирован: 2014.01.14, 09:34

Re: Динамическая проверка прав на основе rbac\DbManager

Сообщение Roksalana »

Какой url вы пытаетесь открыть?
permit/access/p... ? Доступ вы дали только на permit/access/role к остальным доступа нет.
polumerk
Сообщения: 80
Зарегистрирован: 2015.07.09, 16:04

Re: Динамическая проверка прав на основе rbac\DbManager

Сообщение polumerk »

Roksalana писал(а):Какой url вы пытаетесь открыть?
permit/access/p... ? Доступ вы дали только на permit/access/role к остальным доступа нет.
http://afczb/permit/access/permission

я понимаю что дал только к role, вопрос в том почему ошибка о том что нету доступа не формируется.

Вот описания всего процесса:
1)если я делаю в контроллере проверку через can и в конфиге у меня прописан путь в вьюхе ошибок ('errorHandler' => [ 'errorAction' => 'site/error', ) то выглядит все хорошо, вот так:
скриншот
скриншот
can_in_controller.jpg (61.35 КБ) 11086 просмотров
2) если я переношу проверку прав в конфиг приложения (для того что бы работало на лету) то получают вот что:
скриншот
скриншот
errorHandler_errorAction.jpg (214.38 КБ) 11086 просмотров
3) если я удаляю при настройке проверки прав на лету из конфига приложения строку 'errorHandler' => [ 'errorAction' => 'site/error', то тогда получают ошибку вот такого вида:
скриншот
скриншот
as_AccessBehavior_in_config.jpg (50.91 КБ) 11086 просмотров

как добиться при проверке на лету что бы ошибка выглядела как при проверке через can в контроллере?
cmjn1
Сообщения: 3
Зарегистрирован: 2015.08.06, 12:31

Re: Динамическая проверка прав на основе rbac\DbManager

Сообщение cmjn1 »

polumerk писал(а):как добиться при проверке на лету что бы ошибка выглядела как при проверке через can в контроллере?
Тоже столкнулся с этой проблемой, выяснилось:
в классе \developeruz\db_rbac\behaviors\AccessBehavior в методе interception, строка 42: $action = $event->sender->requestedAction;
При вызове действия (например 'site/error') из обработчика ошибок event->sender->requestedAction остается тем же самым (т. е. действие, доступа к которому нет), повторно осуществляется проверка доступа к тому же действию, и опять выбрасывается исключение.
Нужно код поправить, например: $action = $event->sender->controller->action;

И еще: в том же классе в методе createRule в массив $this->_rules[] при повторном вызове добавляются правила, которые там уже есть, нужно проверку добавить.
polumerk
Сообщения: 80
Зарегистрирован: 2015.07.09, 16:04

Re: Динамическая проверка прав на основе rbac\DbManager

Сообщение polumerk »

cmjn1 писал(а):
polumerk писал(а):как добиться при проверке на лету что бы ошибка выглядела как при проверке через can в контроллере?
Тоже столкнулся с этой проблемой, выяснилось:
в классе \developeruz\db_rbac\behaviors\AccessBehavior в методе interception, строка 42: $action = $event->sender->requestedAction;
При вызове действия (например 'site/error') из обработчика ошибок event->sender->requestedAction остается тем же самым (т. е. действие, доступа к которому нет), повторно осуществляется проверка доступа к тому же действию, и опять выбрасывается исключение.
Нужно код поправить, например: $action = $event->sender->controller->action;

И еще: в том же классе в методе createRule в массив $this->_rules[] при повторном вызове добавляются правила, которые там уже есть, нужно проверку добавить.
А проверку на повторение вы делали в правилах при повторном добавлении?
Как же хорошо что вы нашли момент, я там зажимки не верные делал((
cmjn1
Сообщения: 3
Зарегистрирован: 2015.08.06, 12:31

Re: Динамическая проверка прав на основе rbac\DbManager

Сообщение cmjn1 »

polumerk писал(а):А проверку на повторение вы делали в правилах при повторном добавлении?
Сделал просто проверку, что правила не пусты, т. к. конфигурируется компонент 1 раз.
Я сам класс не менял, просто сделал дочерний класс и его использую:

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

namespace common\components\db_rbac\behaviors;

use developeruz\db_rbac\behaviors\AccessBehavior as AccessBehaviorBase;
use ReflectionProperty;
use Yii;
use yii\di\Instance;
use yii\web\BadRequestHttpException;
use yii\web\User;

class AccessBehavior extends AccessBehaviorBase
{
    protected $_rulesReflection;

    public function __construct()
    {
        $this->_rulesReflection = new ReflectionProperty('developeruz\db_rbac\behaviors\AccessBehavior', '_rules');
        $this->_rulesReflection->setAccessible(true);
    }

    public function interception($event)
    {
        $route = Yii::$app->getRequest()->resolve();

        //Проверяем права по конфигу
        $this->createRule();
        /** @var \yii\web\User $user */
        $user = Instance::ensure(Yii::$app->user, User::className());
        $request = Yii::$app->getRequest();
        $action = $event->sender->controller->action;

        if (!$this->cheсkByRule($action, $user, $request)) {
            //И по AuthManager
            if (!$this->checkPermission($route)) {
                if ($user->isGuest) {
                    $user->loginRequired();
                } else {
                    throw new BadRequestHttpException(Yii::t('app', 'Недостаточно прав'));
                }
            }
        }
    }

    protected function createRule()
    {
        if (empty($this->_rulesReflection->getValue($this))) {
            parent::createRule();
        }
    }
}
Пришлось reflection использовать, т. к. свойство "_rules" объявлено как private.
И еще добавил редирект на страницу входа для незалогиненных, чтобы поведение было, как если "access" прописать в "behaviors" контроллера.
polumerk
Сообщения: 80
Зарегистрирован: 2015.07.09, 16:04

Re: Динамическая проверка прав на основе rbac\DbManager

Сообщение polumerk »

Спасибо огромное!!!
Аватара пользователя
Roksalana
Сообщения: 215
Зарегистрирован: 2014.01.14, 09:34

Re: Динамическая проверка прав на основе rbac\DbManager

Сообщение Roksalana »

ОМГ, стоило уехать в отпуск, как в моем модуле нашли баги :( Насколько понимаю проблема только в случаи подключения модуля, как поведения в контроллере?
В любом случаи проверю и постараюсь решить
cmjn1
Сообщения: 3
Зарегистрирован: 2015.08.06, 12:31

Re: Динамическая проверка прав на основе rbac\DbManager

Сообщение cmjn1 »

Roksalana писал(а):В любом случаи проверю и постараюсь решить
Посмотрел исправленный вариант, он будет работать, если подключать в контроллере, но будет повторяться ошибка:
Изображение
Не будет работать, если подключать через общий конфиг.
А мой вариант не будет работать, если подключать в контроллере:))

В итоге как-то так:

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

        if ($event->sender instanceof \yii\web\Application) {
            $action = $event->sender->controller->action;
        } elseif ($event->sender->module instanceof \yii\web\Application) {
            $action = $event->sender->module->controller->action;
        } else {
            throw new BadRequestHttpException(Yii::t('app', 'Неверный класс, вызвавший событие проверки прав доступа'));
        }
Ответить