Очень часто при разработки веб приложений, нам необходимо иметь возможность гибких настроек, над привилегиями пользователей системы.
С этой задачей в YII2 хорошо справляется менеджер RBAC.
Менеджер RBAC бывает 2-типов:
В этой статье мы разберем работу yii\rbac\DbManager, так как по моему мнению он более гибче и практичней чем yii\rbac\PhpManager.
Первым делом нам необходимо подключить данный менеджер в конфиг, не забывайте подключить и в конфигу консольного приложения:
$config = [ //.. 'components' => [ //.. 'authManager' => [ 'class' => 'yii\rbac\DbManager', 'cache' => 'cache' //Включаем кеширование ], 'cache' => [ 'class' => 'yii\caching\FileCache', // Подключаем файловое кэширование данных ], ] //.. ];
Если вы для своих проектов используете кеширование, то для DbManager можно указать дополнительное свойство cache, что позволит существенно снизить нагрузку с бд.
После этого нам необходимо в консоли выполнить команду:
php yii migrate --migrationPath=@yii/rbac/migrations/
Вследствие чего у нас в бд создается 4 таблицы.
Теперь когда мы выполнили миграцию таблиц, нужно добавить несколько ролей (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). Правила добавляет дополнительное ограничение на роли и право. Для создания своего правила, нам необходимо унаследоваться от класса 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. В случаи успеха данный пост будет отредактирован.