Эта статья является дополнением и продолжением предыдущей статьи по авторизации в Yii2. В ней мы рассмотрим контроль доступа к модулям, контроллерам, действиям и отдельным функциям на основе встроенного в Yii2 механизма RBAC.
Для начала нужно сказать о самом главном аспекте RBAC — его области применения, в подавляющем большинстве случаев полноценный контроль доступа на основе ролей нужен для систем, в которых администратору придется динамически изменять права у различных групп пользователей через панель администратора или любой другой интерфейс.
Вторым важным аспектом является понимание терминов с которыми работает RBAC:
- роль (role) — принадлежность пользователя к какой-либо группе, которая определяет его права доступа. Примеры: администратор, модератор, обычный пользователь.
- разрешение (permission) — возможность доступа к какому-либо функционалу. Примеры: открытие страницы, добавление статьи, редактирование личных данных.
- правило (rule) — набор требований к пользователю, которым он должен соответствовать для получения доступа к функционалу. Правила могут крепиться как к роли(role), так и к разрешению(permission). Примеры: проверка авторства статьи перед её редактированием, проверка подтверждения контактных данных покупателя в магазине перед оформлением покупки, проверка возраста пользователя перед заказом билета.
- привязка (assigment) — установка связей между сущностями RBAC. Примеры: привязка роли к пользователю, привязка правила к пользователю.
- наследование (в Yii2 — addChild()) — передача прав доступа (разрешений и правил). Примеры: наследование роли от роли, роли от разрешения.
Давайте перейдем к обзору реализации RBAC в Yii2, точнее к двум её вариантам: PhpManager и DbManager. Различие между этими двумя реализациями состоит в способе хранения данных, в PHP файлах и базе данных соответственно. К плюсам PhpManager’а можно отнести скорость работы на небольшом количестве пользователей из-за хранения всей инфраструктуры менеджера в файлах, но этот плюс постепенно превращается в минус при росте количества пользователей, так как эти файлы начинают расти в размерах. Сильной стороной DbManager’а является гибкое управление политикой доступа (для этих задач обычно реализуется раздел в панели администратора) к функционалу и относительно высокая скорость работы при большом количестве пользователей.
В примерах этой статьи используется шаблон приложения basic.
Для подключения RBAC менеджера нужно настроить компонент в двух файлах конфигурации: «../config/web.php» и «../config/console.php».
return [ // Другие параметры. 'components' => [ 'authManager' => ['class' => 'yii\rbac\DbManager'], // или 'yii\rbac\PhpManager'. // Другие параметры. ], ];
Для функционирования DbManager’а требуется настроенное подключение к БД и применение миграции от разработчиков фреймворка:
yii migrate --migrationPath=@yii/rbac/migrations
А для работы PhpManager’а необходимо лишь наличие директории @app/rbac/ с правами записи для сервера.
После подключения RBAC-менеджера необходимо создать требуемые роли, разрешения и правила, которые можно будет присоединять к пользователю. Для небольших систем эти операции выводят в отдельный контроллер (RbacController например) или в миграцию, но вы можете делать это там, где заходите, разницы никакой нет. А для больших систем часто пишут свою надстройку для управления правами доступа или используют стороннее расширение наподобие yii2-admin.
РОЛИ
Для примера создадим три роли: администратор, модератор и пользователь.
$roleAdministrator = Yii::$app->authManager->createRole('administrator'); $roleAdministrator->description = 'Администратор'; Yii::$app->authManager->add($roleAdministrator); $roleModerator = Yii::$app->authManager->createRole('moderator'); $roleModerator->description = 'Модератор'; Yii::$app->authManager->add($roleModerator); $roleUser = Yii::$app->authManager->createRole('user'); $roleUser->description = 'Пользователь'; Yii::$app->authManager->add($roleUser);
После выполнения кода выше в таблице auth_item (для DbManager) или в файле app/rbac/items (для PhpManager) должны появиться записи для наших ролей. Эти роли уже можно использовать для контроля доступа. Чтобы протестировать работу нашего менеджера привяжем каждую из ролей к разным пользователям.
// Достаем пользователя Иванова из БД. $ivanov = User::findOne(1); // Достаем роль администратора из RBAC-менеджера. $roleAdministrator = Yii::$app->authManager->getRole('administrator'); // Привязываем роль администратора к идентификатору Иванова. Yii::$app->authManager->assign($roleAdministrator, $ivanov->getId()); // Достаем пользователя Петрова из БД. $petrov = User::findOne(2); // Достаем роль модератора из RBAC-менеджера. $roleModerator = Yii::$app->authManager->getRole('moderator'); // Привязываем роль модератора к идентификатору Петрова. Yii::$app->authManager->assign($roleModerator, $petrov->getId()); // Достаем пользователя Сидорова из БД. $sidorov = User::findOne(3); // Достаем роль модератора из RBAC-менеджера. $roleUser = Yii::$app->authManager->getRole('user'); // Привязываем роль пользователя к идентификатору Сидорова. Yii::$app->authManager->assign($roleUser, $sidorov->getId());
В реальных приложениях пользователям присваивают роли при регистрации в системе, здесь же для примера они были добавлены ранее и найдены через findOne() по идентификатору. После выполнения этого кода в таблице auth_assignment (для DbManager) или в файле app/rbac/items (для PhpManager) добавятся записи для связи ролей и пользователей.
Если вы раньше не использовали RBAC менеджер, то скорее всего создавали поле «role» в таблице пользователей и записывали туда присвоенное имя роли. Теперь вся работа с ролями будет происходить через RBAC менеджер и в поле «role» нет надобности.
Давайте создадим две условные страницы для управления статьями и пользователями к которым ограничим доступ некоторым пользователям. К странице управления статьями будет доступ только у администратора, а к управлению статьями будет доступ у администратора и у модератора. Пользователь же останется вообще без доступа.
<?php namespace app\controllers; use yii\web\Controller; use yii\filters\AccessControl; class SiteController extends Controller { public function behaviors() { return [ 'access' => [ 'class' => AccessControl::class, 'only' => ['manage-users', 'manage-articles'], 'denyCallback' => function () { die('Доступ запрещен!'); }, 'rules' => [ [ 'allow' => true, 'actions' => ['manage-users'], 'roles' => ['administrator'], ], [ 'allow' => true, 'actions' => ['manage-articles'], 'roles' => ['administrator', 'moderator'], ], ], ], ]; } public function actionManageUsers() { echo 'Управление пользователями доступно только администратору.'; } public function actionManageArticles() { echo 'Управление статьями доступно администратору и модератору.'; } }
Если вам ранее приходилось использовать фильтры контроля доступа (ACF), то представленный выше способ ограничения доступа покажется знакомым за одним исключением — появилась возможность указывать свои роли в параметре «roles» вместо двух стандартных @ и ?.
РАЗРЕШЕНИЯ
Разрешения позволят нам более гибко управлять доступом. Продолжим развивать предыдущий пример: создадим разрешение на доступ к странице управления пользователями (SiteController/ManageArticles) и добавим его к роли модератора, что бы Петров тоже мог видеть всех пользователей:
// Создаем разрешение на доступ к странице управления пользователями. $permissionManageUsers = Yii::$app->authManager->createPermission('view_manage_users_page'); // Добавляем своё описание к разрешению, чтобы не забыть для чего мы его создавали. $permissionManageUsers->description = 'Доступ к странице управления пользователями.'; // Добавляем разрешение в систему через RBAC менеджер. Yii::$app->authManager->add($permissionManageUsers); // Ищем роль модератора. $roleModerator = Yii::$app->authManager->getRole('moderator'); // Добавляем (наследуем) разрешение для роли модератора. Yii::$app->authManager->addChild($roleModerator, $permissionManageUsers);
После создания и привязки разрешения мы можем начать с ней работать. Есть два варианта: через ACF и через метод «can()» в компоненте «User».
public function behaviors() { return [ 'access' => [ 'class' => AccessControl::class, 'only' => ['manage-users'], 'denyCallback' => function () { die('Доступ запрещен!'); }, 'rules' => [ [ 'allow' => true, 'actions' => ['manage-users'], 'roles' => ['view_manage_users_page'], // Разрешения как и роли можно использовать тут. ], ], ], ]; } public function actionManageUsers() { echo 'Управление пользователями доступно только администратору.'; }
Через метод «can()» в компоненте «User»:
public function actionManageUsers() { if (Yii::$app->user->can('view_manage_users_page')) { echo 'Доступ есть.'; } else { echo 'Доступ закрыт.'; } echo 'Управление пользователями доступно только администратору.'; }
С помощью разрешений вы без труда сможете контролировать доступ не только к целым модулям, контроллерам или действиям, но и к частям представлений.
ПРАВИЛА
Правила в RBAC являются «вишенкой на торте» в управлении доступом, так как они позволяют еще точнее задать условия доступа для каждой роли и даже для отдельного пользователя. Еще больше разовьем наш пример и задействуем последнего пользователя — Сидорова, который пока не принимал участия в работе на системой. Дадим возможность редактировать свои статьи всем пользователям.
Для начала создадим само правило проверки авторства статьи:
<?php namespace app\components\rbac; use yii\rbac\Rule; class OwnerRule extends Rule { public $name = 'isOwner'; /** * Проверка авторства статьи. * * @param string|int $user Идентификатор пользователя. * @param Item $item Роль или разрешение ассоциированное с этим правилом. * @param array $params Параметры. * * @return bool Результат проверки, вернет true или false. */ public function execute($user, $item, $params) { if (!isset($params['article'])) { return false; } return $params['article']->user_id == $user; } }
Теперь добавим это правило в систему и прикрепим к роли пользователя:
// Достаем пользователя Сидорова из БД. $sidorov = User::findOne(3); // Достаем роль модератора из RBAC-менеджера. $roleUser = Yii::$app->authManager->getRole('user'); // Привязываем роль пользователя к идентификатору Сидорова. Yii::$app->uthManager->assign($roleUser, $sidorov->getId()); // Создаем объект класса нашего правила (листинг этого класса ниже). $ruleCheckOwner = new OwnerRule(); // Добавляем правило в систему. Yii::$app->authManager->add($ruleCheckOwner); // Создаем разрешение "update_own_article" для владельцев статей. $updateOwnArticle = Yii::$app->authManager->createPermission('update_own_article'); // Добавляем своё описание, чтобы не забыть зачем мы создавали это правило. $updateOwnArticle->description = 'Правило для проверки авторства статьи.'; // Добавляем наименование используемого правила в наше разрешение. $updateOwnArticle->ruleName = $ruleCheckOwner->name; // Добавляем разрешение в систему. Yii::$app->authManager->add($updateOwnArticle); // Прикрепляем к роли пользователя право редактировать свои статьи. $auth->addChild($roleUser, $updateOwnArticle);
Осталось опробовать наше правило:
<?php namespace app\controllers; use yii\web\Controller; use app\models\Article; class SiteController extends Controller { public function actionManageArticle() { // В тестовой базе данных только одна статья и её автором является Сидоров. $article = Article::findOne(1); if (\Yii::$app->user->can('update_own_article', ['article' => $article])) { echo 'Этот пользователь может редактировать статью.'; } else { echo 'Статья не принадлежит пользователю.'; } } }
На этом описание работы встроенного в Yii2 RBAC менеджера закончено. Если вам показалось, что в управлении доступом на основе ролей трудно разобраться, то это только первое впечатление, оно когда-то было и у меня. После пары часов практики все должно проясниться, главное начать пробовать.
Добавить комментарий
Для отправки комментария вам необходимо авторизоваться.