Yii2 - Добавление RBAC на сайт, контроль доступа на основе ролей
Коллеги всем привет.
В сегодняшней статье мы поговорим о том как настроить RBAC в yii2. Если кто не знает, то RBAC это один из компонентов в yii2 который отвечает за контроль доступа на основе ролей. К примеру у вас есть какое-то действие и нужно проверить, имеет ли право текущий пользователь выполнять это действия или нет. Глубина наследований в RBAC практически не имеет границ, можно создавать сколько угодно ролей и потом присваивать их пользователям.
По умолчанию RBAC в yii2 выключен. И так давайте его настроим.
Первое что вам нужно знать о RBAC это то что его правила могут храниться как в обычном файле, так и в базе данных.
- yii\rbac\PhpManager - Хранения правил в файлах.
- yii\rbac\DbManager - Хранения правил в базе данных.
В этой статье я буду показывать работу yii\rbac\DbManager, так как по моему он более практичный чем yii\rbac\PhpManager.
Первый шаг по настройки RBAC это нужно его включить в конфигурационном файле web.php и console.php.
'authManager' => [
'class' => 'yii\rbac\DbManager',
'cache' => 'cache'
]
Помимо самого RBAC мы еще включаем кеширование свойством 'cache' => 'cache' чтобы снизить нагрузку на базу данных.
Следующим действием нам нужно подготовить базу данных для rbac. rbac в своей роботе будет использовать 4 таблицы, и нам нужно будет их создать.
- auth_item: таблица содержит role/permitssion и их описание.
- auth_item_child: хранит наследования role/permitssion друг от друга.
- auth_assignment: тут данные о назначении пользователям role/permitssion.
- auth_rule: хранения индивидуальных правил.
Мы можем создать эти таблицы двумя способами.
Первый способ это выполнить команду миграции в консоли которая создаст таблицы автоматически:
php yii migrate --migrationPath=@yii/rbac/migrations/
Второй способ это создать эти таблицы вручную:
CREATE TABLE `auth_assignment` (
`item_name` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
`user_id` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
`created_at` int(11) DEFAULT NULL,
PRIMARY KEY (`item_name`,`user_id`),
KEY `idx-auth_assignment-user_id` (`user_id`),
CONSTRAINT `auth_assignment_ibfk_1` FOREIGN KEY (`item_name`)
REFERENCES `auth_item` (`name`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE `auth_item` (
`name` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
`type` smallint(6) NOT NULL,
`description` text COLLATE utf8_unicode_ci DEFAULT NULL,
`rule_name` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
`data` blob DEFAULT NULL,
`created_at` int(11) DEFAULT NULL,
`updated_at` int(11) DEFAULT NULL,
PRIMARY KEY (`name`),
KEY `rule_name` (`rule_name`),
KEY `idx-auth_item-type` (`type`),
CONSTRAINT `auth_item_ibfk_1` FOREIGN KEY (`rule_name`)
REFERENCES `auth_rule` (`name`) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE `auth_item_child` (
`parent` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
`child` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`parent`,`child`),
KEY `child` (`child`),
CONSTRAINT `auth_item_child_ibfk_1` FOREIGN KEY (`parent`)
REFERENCES `auth_item` (`name`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `auth_item_child_ibfk_2` FOREIGN KEY (`child`)
REFERENCES `auth_item` (`name`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE `auth_rule` (
`name` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
`data` blob DEFAULT NULL,
`created_at` int(11) DEFAULT NULL,
`updated_at` int(11) DEFAULT NULL,
PRIMARY KEY (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
Теперь когда мы включили rbac и создали таблицы то теперь давайте создадим несколько ролей.
Первая роль у нас будет называться Admin.
$role = Yii::$app->authManager->createRole('admin');
$role->description = 'Admin';
Yii::$app->authManager->add($role);
Вторую роль мы назовем Manager.
$role = Yii::$app->authManager->createRole('author');
$role->description = 'Manager';
Yii::$app->authManager->add($role);
Теперь когда мы создали пару ролей на нашем сайте то теперь мы можем их использовать в фильтре AccessControl, для настройки доступа.
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'rules' => [
[
'actions' => ['adminpanel'],
'allow' => true,
'roles' => ['admin'],
],
],
]
];
}
Этим кодом мы указываем что доступ к действию adminpanel можно получить только тем пользователям которые имеют роль admin. Но пользователя с такой ролью у нас пока нет, а есть только роль.
Еще одна особенность rbac в том что мы можем создавать не только роли, но и права. Права создаются точно так же как и роли.
$permit = Yii::$app->authManager->createPermission('grantModerator');
$permit->description = 'Grant moderator';
Yii::$app->authManager->add($permit);
Yii2 сам не будет проверять права пользователя. Имя "grantModerator" - просто обычная строка, она никак не соотносится с action и другими сущностями в Yii2. Проверять, имеет ли право пользователь на действия вы должны сами.
if(Yii::$app->user->can('grantModerator'))
{
//perform some action
}
else throw new ForbiddenHttpException('You do not have sufficient rights to perform the specified action');
В Yii2 роли и права можно наследовать, причем без ограничений, что от чего наследуется.
Наследовать можно:
- роль от роли
- роль от права
- право от роли
- право от права
Теперь настало время привязать нашу роль какому-нибудь пользователю, в моем случаи я буду привязывать роль admin к пользователю administrator. Привязка осуществляется по ID пользователя в базе данных и делается это один раз. rbac сохранит данные в таблицу auth_assignment и будет подхватывать роль автоматически при авторизации пользователя. Привязку лучше всего делать при создании нового пользователя.
$userRole = Yii::$app->authManager->getRole('admin');
Yii::$app->authManager->assign($userRole, Yii::$app->user->getId());
Привязывать к пользователю можно не только роли, но и права.
$permit = Yii::$app->authManager->getPermission('grantModerator');
Yii::$app->authManager->assign($permit, Yii::$app->user->getId());
Привязка права осуществляется так же по ID пользователя в базе данных и делается это один раз.
У пользователя может быть несколько ролей. Чтобы получить все роли пользователя можно сделать вот так:
Yii::$app->authManager->getRolesByUser(Yii::$app->user->getId());
Всем спасибо, я надеюсь что вам моя статья хоть чем-то помогла.