<? phpukraine СПІВБЕСІДИ
Пошук по платформі
YII · MIDDLE

Як реалізовано RBAC у Yii2?

RBAC у Yii2 будується на ієрархії ролей і дозволів з правилами: ієрархія зберігається в БД або файлі, перевірка йде через Yii::$app->user->can(), а правила додають динамічні умови на кшталт авторства.

Чим правило (rule) відрізняється від permission?
Як зберігати RBAC-дерево: в БД чи у файлах?
Як зробити, щоб автор міг редагувати лише свої пости?
RBAC авторизація Yii 2

RBAC у Yii2 складається з трьох видів елементів. Permission — атомарна дія на кшталт updatePost. Role — група дозволів або інших ролей: author, admin. Rule — клас із методом execute(), який під час перевірки отримує користувача, елемент і параметри й повертає bool. Разом вони утворюють орієнтований граф, і Yii::$app->user->can('updatePost', ['post' => $post]) шукає шлях від призначень користувача до потрібного дозволу, виконуючи правила на кожному вузлі.

Правила роблять RBAC динамічним. Дозвіл updateOwnPost з правилом AuthorRule є дочірнім для updatePost: автор проходить до updatePost лише тоді, коли правило підтверджує, що пост його. Адміністратор отримує updatePost напряму без умов. Так авторство описується один раз у графі, а не через if у кожному екшні.

Ієрархія зберігається в DbManager або PhpManager, які реалізують один інтерфейс. Для продакшену з динамічними призначеннями потрібен DbManager з увімкненим кешем, інакше кожна перевірка робить кілька запитів до auth-таблиць. PhpManager підходить для невеликих застосунків із фіксованими ролями і дозволяє тримати права в git.

У коді перевіряють дозволи, а не ролі: can('updatePost'), а не can('admin'). Тоді зміна ролей не вимагає правки коду, а при міграції на Laravel чи Symfony дозволи з правилами майже один в один стають Policies або Voters.

// Правило: дозвіл спрацьовує лише для власного поста
final class AuthorRule extends yii\rbac\Rule
{
    public $name = 'isAuthor';

    public function execute($user, $item, $params): bool
    {
        return isset($params['post']) && $params['post']->author_id == $user;
    }
}

// Консольна команда: будуємо ієрархію один раз
$auth = Yii::$app->authManager;

$updatePost = $auth->createPermission('updatePost');
$auth->add($updatePost);

$rule = new AuthorRule;
$auth->add($rule);

$updateOwnPost = $auth->createPermission('updateOwnPost');
$updateOwnPost->ruleName = $rule->name;
$auth->add($updateOwnPost);
$auth->addChild($updateOwnPost, $updatePost);   // updateOwnPost => updatePost за умови правила

$author = $auth->createRole('author');
$auth->add($author);
$auth->addChild($author, $updateOwnPost);

$admin = $auth->createRole('admin');
$auth->add($admin);
$auth->addChild($admin, $updatePost);          // admin редагує будь-який пост
$auth->addChild($admin, $author);

$auth->assign($author, 15);

// У контролері: перевіряємо дозвіл, а не роль
if (! Yii::$app->user->can('updatePost', ['post' => $post])) {
    throw new ForbiddenHttpException('Not your post.');
}
Структуру: permission це атомарна дія, role групує permissions або інші ролі, і разом вони утворюють орієнтований граф, де can() шукає шлях від призначень користувача до потрібного дозволу.
Що rule це клас із execute(), який отримує користувача, елемент і параметри й повертає bool, тому дозвіл updateOwnPost з правилом AuthorRule перевіряє, що пост належить користувачу.
Різницю сховищ: DbManager для продакшену з кешем, PhpManager для невеликих застосунків без динамічних призначень, і що обидва реалізують один інтерфейс.
Що перевірка викликається в контролерах через AccessControl-фільтр або явний can(), а призначення ролей робиться в консольній команді або адмінці.
Уміння порівняти з Voters у Symfony, Gates і Policies у Laravel, і розуміння, як перенести правила при міграції.
Плутати RBAC з AccessControl-фільтром по ролях '@' і '?': фільтр лише вирішує, кого пускати в екшн, а RBAC описує ієрархію дозволів.
Перевіряти ролі замість дозволів: can('admin') замість can('updatePost'), через що зміна ролей вимагає правки коду.
Забувати про кеш DbManager і робити десятки запитів до auth-таблиць на кожен запит.
Реалізовувати авторство через if ($post->author_id === Yii::$app->user->id) у кожному екшні замість правила.
Не розуміти, що rule виконується для кожного елемента на шляху, і важкі запити в execute() виконуються багато разів.
ПОРАДА

Порівняйте з Voters у Symfony або Policies у Laravel: питання про перенесення логіки прав при міграції задають часто. І скажіть, що в коді перевіряєте дозволи, а не ролі.

оновлено 3 вересня 2026 · ліцензія CC-BY-SA-4.0 Знайшли неточність? Напишіть →
ПЕРЕВІРТЕ СЕБЕ

Ролі й дозволи утворюють дерево, а правила додають динамічні умови, наприклад авторство.