Инструменты пользователя

Инструменты сайта


yii2:rbac

Назад

Введение

Очень часто при разработки веб приложений, нам необходимо иметь возможность гибких настроек, над привилегиями пользователей системы.
С этой задачей в YII2 хорошо справляется менеджер RBAC.
Менеджер RBAC бывает 2-типов:

  • yii\rbac\PhpManager - Основанный на хранения в файлах.
  • yii\rbac\DbManager - Основанный на хранения в БД.

В этой статье мы разберем работу yii\rbac\DbManager, так как по моему мнению он более гибче и практичней чем yii\rbac\PhpManager.

Настройка RBAC

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

$config = [
    //..
    'components' => [
        //..
        'authManager' => [
            'class' => 'yii\rbac\DbManager',
            'cache' => 'cache' //Включаем кеширование 
        ],
        'cache' => [
            'class' => 'yii\caching\FileCache',  // Подключаем файловое кэширование данных
        ],
    ]
    //..
];

Если вы для своих проектов используете кеширование, то для DbManager можно указать дополнительное свойство cache, что позволит существенно снизить нагрузку с бд.

После этого нам необходимо в консоли выполнить команду:

php yii migrate --migrationPath=@yii/rbac/migrations/

Вследствие чего у нас в бд создается 4 таблицы.

Назначения таблиц RBAC

  • таблица auth_item: содержит role/permitssion и их описание.
  • таблица auth_item_child: содержит наследования role/permitssion друг от друга.
  • таблица auth_assignment: хранит данные о назначении пользователям role/permitssion.
  • Таблица auth_rule: для хранения индивидуальных правил.

Настройка Role и Permission

Теперь когда мы выполнили миграцию таблиц, нужно добавить несколько ролей (role).

$role = Yii::$app->authManager->createRole('admin');
$role->description = 'Администратор';
Yii::$app->authManager->add($role);
 
$role = Yii::$app->authManager->createRole('author');
$role->description = 'Автор';
Yii::$app->authManager->add($role);

Теперь когда у нас появились новые роли в системе, мы можем их использовать в фильтр AccessControl, для настройки доступа.

public function behaviors()
{
    return [
        'access' => [
            'class' => AccessControl::className(),
            'rules' => [
                [
                    'actions' => ['adminka'],
                    'allow' => true,
                    'roles' => ['admin'],
                ],
            ],
        ]
    ];
}

Доступ к actionAdminka доступен только пользователю с ролью admin. Но пользователя с такой ролью у нас пока нет. Пока есть только роль. Что еще важно: создавать можно не только роль, но и отдельные право (Permission).
Создаются они так же как и роли:

$permit = Yii::$app->authManager->createPermission('createPost');
$permit->description = 'Право на создании поста';
Yii::$app->authManager->add($permit);

Yii не проверяет сам права. Имя «createPost» — просто строка, она никак не соотносится с action и другими сущностями Yii. Проверять, имеет ли право юзер на действия вы должны сами.

if(\Yii::$app->user->can('createPost'))
{
    //выполняем какое то действие
}
else throw new ForbiddenHttpException('У вас недостаточно прав для выполнения указанного действия');

Наследования ролей и прав

Роли и права можно наследовать. Причем без ограничений что от чего наследуется.

$role = Yii::$app->authManager->getRole($name);
$permit = Yii::$app->authManager->getPermission($permit);
Yii::$app->authManager->addChild($role, $permit);

Наследовать можно:

  • роль от роли
  • роль от права
  • право от роли
  • право от права

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

Привязка ролей к пользователю

Назначение роли так же делается через authManager.

$userRole = Yii::$app->authManager->getRole('name_of_role');
Yii::$app->authManager->assign($userRole, Yii::$app->user->getId());

И делается 1 раз. RBAC сохранит данные в auth_assignment и будет подхватывать роль автоматически при авторизации пользователя. Поэтому привязку лучше всего делать при заведении пользователя.
Важно то, что привязывать к пользователю можно не только роль, но и право.

$permit = Yii::$app->authManager->getPermission('name_of_permitssion');
Yii::$app->authManager->assign($permit, Yii::$app->user->getId());

У пользователя может быть несколько ролей. Получить их всех можно вот так:

Yii::$app->authManager->getRolesByUser(Yii::$app->user->getId())

Использование (Rules)

Теперь когда мы научились использовать роли и право , мы можем приступить к рассмотрению использования правил (Rules). Правила добавляет дополнительное ограничение на роли и право. Для создания своего правила, нам необходимо унаследоваться от класса yii\rbac\Rule и реализовать метод execute().

namespace app\rbac;
 
use yii\rbac\Rule;
 
class AuthorRule extends Rule
{
    public $name = 'isAuthor'; // Имя правила
 
    public function execute($user_id, $item, $params)
    {
        return isset($params['post']) ? $params['post']->createdBy == $user_id : false;
    }
}

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

$auth = Yii::$app->authManager;
 
// добовляем правило
$rule = new \app\rbac\AuthorRule;
$auth->add($rule);
 
// добавляем право "updateOwnPost" и связываем правило с ним
$updateOwnPost = $auth->createPermission('updateOwnPost');
$updateOwnPost->description = 'Редактировать посты';
$updateOwnPost->ruleName = $rule->name;
$auth->add($updateOwnPost);
 
// "updateOwnPost" наследует право "updatePost"
$updatePost = Yii::$app->authManager->getPermission('updatePost');
$auth->addChild($updateOwnPost, $updatePost);
 
$author = Yii::$app->authManager->getRole('author');
// и тут мы позволяем автору редактировать свои посты
$auth->addChild($author, $updateOwnPost);

Теперь мы для проверке в коде пишем следующий код

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

Как мы видим правило updatePost принимает модель post, где updatePost передаёт на обработку праву updateOwnPost а он в свою очередь вызывает правило AuthorRule и запускает метод execute() который возвращает true/false. В случаи успеха данный пост будет отредактирован.