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/permission.
- 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());
Дякую всім, я сподіваюся що вам моя стаття хоч чимось допомогла.