
RBAC же позволяет разделить авторизованных пользователей на отдельные группы, давая каждой из них отдельные права. Названия и количество таких групп не ограничено.
В данной статье рассмотрим PhpManager, представляющий собой диспетчер авторизации Yii2 хранящий данные о ролях и правилах в файлах.
Данный менеджер является одним из стандартных механизмов компонента приложения 'authManager' и рекомендуется для использования если приложение не требует слишком динамичного управления ролями и разрешениями, то есть для большинства приложений.
Создание доступа.
Создадим, для примера, 3 группы пользователей:
- администратор;
- модератор;
- простой пользователь.
- \common\models\User.php
- \common\models\LoginForm.php

Если роли не нужны и кроме админа никого не нужно авторизовывать, то можно на этом и остановиться, но "Шурик, это не наш метод" :-)
Функциональность RBAC обеспечивает компонент приложения AuthManager, настроим его.
Допустим, что наши настройки ролей будут храниться в папке common\components\rbac. Запишем данный код в файл common\config\main.php следующим массивом после cache:
'components' => [ 'authManager' => [ 'class' => 'yii\rbac\PhpManager', //зададим куда будут сохраняться наши файлы конфигураций RBAC 'itemFile' => '@common/components/rbac/items.php', 'assignmentFile' => '@common/components/rbac/assignments.php', 'ruleFile' => '@common/components/rbac/rules.php' ], ... ],
Для создания ролей удобнее всего использовать консольное приложение.
Для этого создадим контроллер в файле console\controllers\RbacController.php, который будет генерировать RBAC при его запуске. Так же, для примера, создадим одно из разрешений (доступ к админ-панели) и дадим его модератору и администратору.
<?php namespace console\controllers; use Yii; use yii\console\Controller; use common\components\rbac\UserRoleRule; class RbacController extends Controller { public function actionInit() { $auth = Yii::$app->authManager; $auth->removeAll(); //удаляем старые данные //Создадим для примера права для доступа к админке $dashboard = $auth->createPermission('adminPanel'); $dashboard->description = 'Админ панель'; $auth->add($dashboard); //Добавляем роли $user = $auth->createRole('user'); $user->description = 'Пользователь'; $auth->add($user); $moder = $auth->createRole('moder'); $moder->description = 'Модератор'; $auth->add($moder); //Добавляем потомков $auth->addChild($moder, $user); $auth->addChild($moder, $dashboard); $admin = $auth->createRole('admin'); $admin->description = 'Администратор'; $auth->add($admin); $auth->addChild($admin, $moder); } }аналогично доступу к админ-панели можно, для разных пользователей, создавать разрешения "createPost", "updatePost" и тд.
Генерирование файлов разрешений.
Теперь открываем консоль, переходим в основную папку yii нашего проекта. И выполняем команду, которая вызовет наш созданный контроллер Rbac и экшен Init.
yii rbac/initгде rbac – название консольного контроллера, а init – название действия.
На самом деле, контроллер не обязательно создавать в консоли, можно создать его в backend или frontend, просто тогда придется вызывать действие напрямую в адресной строке или делать ссылку на него, также, возможно, придется создавать подходящее правило UrlManager()... Кроме того, выполняя код данного класса каждый раз будет перезаписываться файл rules.php из папки rbac, что не очень хорошо. А выполнив его единожды из консоли избежим описанных проблем.
В папке rbac должно появиться 3 файла. В одном из них (items.php) можно просмотреть структуру созданных ролей.
Файл rules.php создался пустым, т.к. на данном этапе не созданы правила проверки прав. Пример создание правил будет дан ниже.
Файл assignments.php создался пустым, т.к. на данный момент у нас еще не привязаны роли к пользователям. Исправим это. Разумеется, у вас уже должна быть таблица User в базе данных, к элементам которой будут привязываться роли. Поэтому выполните миграцию (если еще не выполняли) по созданию данной таблицы, а так же создайте хотя бы одного пользователя, со значением поля username, например с «admin».
Теперь создадим другой консольный контроллер для привязки ролей к пользователям, т.к. на данном этапе пользователь с именем «admin» ничем не отличается от любого другого пользователя кроме названия.
Файл console/controllers/RolesController.php:
<?php namespace console\controllers; use common\models\User; use Yii; use yii\console\Controller; use yii\console\Exception; use yii\helpers\ArrayHelper; class RolesController extends Controller { public function actionAssign() { $username = $this->prompt('Username:', ['required' => true]); $user = $this->findModel($username); $roleName = $this->select('Role:', ArrayHelper::map(Yii::$app->authManager->getRoles(), 'name', 'description')); $authManager = Yii::$app->getAuthManager(); $role = $authManager->getRole($roleName); $authManager->assign($role, $user->id); $this->stdout('Done!' . PHP_EOL); } public function actionRevoke() { $username = $this->prompt('Username:', ['required' => true]); $user = $this->findModel($username); $roleName = $this->select('Role:', ArrayHelper::merge( ['all' => 'All Roles'], ArrayHelper::map(Yii::$app->authManager->getRolesByUser($user->id), 'name', 'description')) ); $authManager = Yii::$app->getAuthManager(); if ($roleName == 'all') { $authManager->revokeAll($user->id); } else { $role = $authManager->getRole($roleName); $authManager->revoke($role, $user->id); } $this->stdout('Done!' . PHP_EOL); } private function findModel($username) { if (!$model = User::findOne(['username' => $username])) { throw new Exception('User is not found'); } return $model; } }
В действиях данного контроллера применяются консольные методы для взаимодействия с пользователем (prompt, select, stdout).
Запустим действие привязки ролей:
yii roles/assignНа запрос консоли нужно будет ввести название пользователя и далее выбрать одну из ролей, которую необходимо привязать к данному пользователю.

В данном случае была привязана роль admin к одноименному пользователю. После этого в файл assignments.php попадет информация связывающая id данного пользователя с ролью.
<?php return [ 1 => [ 'admin', ], ];
Изменив, немного, метод findModel() можно сделать, чтобы вместо имени пользователей, при привязывании к ним ролей, можно было указывать id данных пользователей.
Если нужно, можно привязать к пользователю сразу несколько ролей.
Метод actionRevoke() служит для отвязки ролей от пользователей, т.е. он просто удаляет выбранную роль или сразу все для определенного пользователя.
Контроллер RolesController создан с целью удобства и наглядности привязки ролей. Т.е. вы вполне можете его не создавать, а заполнить массив в файле assignments.php вручную, указав роли для пользователей.
Так же, можно динамически назначить роли пользователям. Например присвоим роль "admin" текущему пользователю:
$userId = Yii::$app->user->id; //id текущего пользователя $userRole = Yii::$app->authManager->getRole('admin'); Yii::$app->authManager->assign($userRole, $userId);Привязка роли делается только 1 раз, повторно выполнить данную команду не получится, т.к. данные уже будут сохранены в файле assignments.php.
Поэтому привязку лучше всего делать при заведении пользователя.
Выше указана стандартная схема работы с RBAC с использованием компонента PhpManager. Как видно, все данные сохраняются в файлах, а база данных используется исключительно для аутентификации пользователей (перечня существующих пользователей к которым можно привязать роли). Исходя из этого можно сделать вывод, что создание роли для каждого пользователя (используя PhpManager) создает в файле дополнительный ассоциативный массив, а то и не один, если ролей привязывается сразу несколько. Если пользователей не много, это не проблема. В противном случае данный файл слишком разрастется, а кроме того не очень удобно работать с присвоением/удалением ролей. Поэтому, часто, немного модифицируют работу с компонентом PhpManager, откажемся от хранения информации о привязанных ролях в данном файле, о чем и поговорим.
Такой подход является промежуточным между PhpManager (согласно которому данные хранятся в файлах) и DbManager (который сохраняет всё в таблицах в базе данных).
Выполнив стандартную миграцию у вас появилась таблица user без поля "role". Добавляем дополнительное поле “role”, в которое будем сохранять роль для каждого пользователя.
Есть 2 подхода в создании типа данного поля - одни сохраняют в него числовое значение, которое связывают с определенной ролью, что так же позволяет позже изменить роль не меняя числовые значения в БД. Но, если вы точно знаете какие роли у вас будут, то удобнее и нагляднее писать в данное поле название конкретной роли (admin,moder,user и др.) В зависимости от выбраного подхода и выберите тип поля – числовое значение или строка (varchar). Рассмотрим сначала второй вариант.
Так же, не забудьте добавить проверку данного поля в модель User.
Используем все те же 3 роли:
- user;
- moder;
- admin.
Данный подход использует установку параметра defaultRoles (роли по-умолчанию) для компонента приложения authManager. Роль по умолчанию — это роль, которая неявно присваивается всем пользователям. Вызов метода [[yii\rbac\ManagerInterface::assign()]] не требуется, и авторизационные данные не содержат информации о назначении. Роль по умолчанию, обычно, связывают с правилом, определяющим к какой роли принадлежит каждый пользователь.
Для этого в файл common/config/main.php, в массив authManager, добавим строку с указанием используемых ролей:
'defaultRoles' => ['user','moder','admin'],
Далее установим названия ролей в виде констант модели User:
class User extends ActiveRecord implements IdentityInterface { const STATUS_DELETED = 0; const STATUS_ACTIVE = 10; const ROLE_USER = 'user'; const ROLE_MODER = 'moder'; const ROLE_ADMIN = 'admin'; …
Далее переделаем консольный контролле создающий роли.
Файл console\controllers\RbacController.php:
<?php namespace console\controllers; use Yii; use yii\console\Controller; use common\components\rbac\UserRoleRule; class RbacController extends Controller { public function actionInit() { $auth = Yii::$app->authManager; $auth->removeAll(); //удаляем старые данные //Создадим для примера права для доступа к админке $dashboard = $auth->createPermission('adminPanel'); $dashboard->description = 'Админ панель'; $auth->add($dashboard); //Добавляем объект определяющий правила для ролей пользователей, он будет сохранен в файл rules.php $rule = new UserRoleRule(); $auth->add($rule); //Добавляем роли $user = $auth->createRole('user'); $user->description = 'Пользователь'; $user->ruleName = $rule->name; $auth->add($user); $moder = $auth->createRole('moder'); $moder->description = 'Модератор'; $moder->ruleName = $rule->name; $auth->add($moder); //Добавляем потомков $auth->addChild($moder, $user); $auth->addChild($moder, $dashboard); $admin = $auth->createRole('admin'); $admin->description = 'Администратор'; $admin->ruleName = $rule->name; $auth->add($admin); $auth->addChild($admin, $moder); } }Видим, что в данном коде создается объект класса правил:
$rule = new UserRoleRule(); $auth->add($rule);идентификатор (название) которого потом сохраняется для каждой роли:
$admin->ruleName = $rule->name;
Создаем данный класс данных правил, который, в обязательном порядке, наследуется от класса Rule, должен содержать уникальное имя в переменной $name и реализовывать метод execute().
Файл common/components/rbac/UserRoleRule.php:
<?php namespace common\components\rbac; use Yii; use yii\rbac\Rule; use yii\helpers\ArrayHelper; use common\models\User; /* * Создаем класс правил. * Сравнивается роль текущего пользователя с ролью, которая необходима для получения доступа */ class UserRoleRule extends Rule { public $name = 'userRole'; //название данного правила /* * $user - id текущего пользователя * $item - объект роли которую проверяем у текущего пользователя * $params - параметры, которые можно передать для проведеня проверки в данный класс */ public function execute($user, $item, $params) { //Получаем объект текущего пользователя из базы $user = ArrayHelper::getValue($params, 'user', User::findOne($user)); if ($user) { $role = $user->role; if ($item->name === 'admin') { return $role == User::ROLE_ADMIN; } elseif ($item->name === 'moder') { return $role == User::ROLE_ADMIN || $role == User::ROLE_MODER; } elseif ($item->name === 'user') { return $role == User::ROLE_ADMIN || $role == User::ROLE_MODER || $role == User::ROLE_USER; } } return false; } }Тут можно увидеть, что для получения доступа по роли 'admin' необходимо, чтобы у текущего пользователя в поле role базы данных был вписан идентификатор полученный вызовом User::ROLE_ADMIN. А вот для доступа по роли 'user' достаточно любого из 3-х идентификаторов.
Теперь файл assignments.php, созданный при выполнении метода консольного контроллера RbacController, содержит пустой массив и он не используется для определения роли текущего пользователя, а вместо него используется проверка из созданного класса правил.
При таком изменении стандартной работы PhpManager не будут работать getRolesByUser(), assign() и некоторые другие системные методы. Если вы их собираетесь использовать, то необходимо доработать PhpManager на получение роли из этого поля (вместо файла assignments.php). Но в большинстве случаев в этом нет необходимости.
Чтобы назначить пользователям роли, достаточно выполнить SQL запрос меняющий значение в поле role нужного пользователя. Это удобно делать создав соответствующий функционал в админ-панели. Конечно, можно слегка изменить второй консольный контроллер - RolesController, код которого я приводил выше, а именно дописать соответствующие SQL запросы и снова использовать консольный интерфейс для создания ролей.
Если вместо указания название роли в поле role вы все же предпочли использовать числовой идентификатор, то нужно всего лишь изменить значения констант в модели User:
const ROLE_USER = 1;
const ROLE_MODER = 5;
const ROLE_ADMIN = 10;
Соответственно для роли пользователя в поле role базы данных должно находиться значение 1, для модератора 5 и тд.
На этом создание ролей и правил завершено, осталось научиться их использовать.
Использование (проверка доступа).
Способ 1. В методе контроллера, в файле-представлении и тд.:
if (Yii::$app->user->can('admin')) { exit ('Привет, Админ!'); } else { exit ('Ты - не админ!'); }Нужно учесть, что если текущий пользователь имеет права админа, то проверка на 'moder' и 'user' даст TRUE, т.к. admin включает в себя их права.
Так же можно проверить разрешение на выполнение определенного действия:
public function actionCreate() { if (!\Yii::$app->user->can('createPost')) { throw new \yii\web\ForbiddenHttpException('Доступ закрыт.'); } return $this->render('create'); }
Способ 2. Если доступ нужно ограничить для каждого действия (или большинства), можно прописать проверку в методе beforeAction() нужного контроллера, чтобы не писать
if !\Yii::$app->user->can
в каждом методе:
public function beforeAction($action) { if (parent::beforeAction($action)) { if (!\Yii::$app->user->can('admin')) { throw new \yii\web\ForbiddenHttpException('Доступ закрыт.'); } return true; } else { return false; } }данный метод выполняется автоматически перед выполнением любого действия.
Способ 3. Создание массива access в методе behaviors() нужного контроллера с указанием к каким действиям нужно ограничить доступ и для кого он разрешен или запрещен:
public function behaviors() { return [ 'access' => [ 'class' => AccessControl::className(), 'rules' => [ [ 'allow' => true, 'actions' => ['index', 'contact'], 'roles' => [User::ROLE_ADMIN], ], ], ], ]; }В данном примере доступ к действиям 'index' и 'contact' разрешен только для пользователя с ролью "admin" (значение константы из модели User).
Способ 4. Можно вынести проверку за пределы контроллера и разместить в отдельном классе. Варианты подключения этого класса могут быть разные, но, пожалуй, самым правильным будет подключить его с помощью поведений Yii2. Подробнее про поведения тут.
Разместим его в папке с другими файлами RBAC - common\components\rbac\verify.php:
<?php namespace common\components\rbac; use Yii; use yii\base\Behavior; use yii\web\ForbiddenHttpException; class Verify extends Behavior { public $actions = null; public function events() { return [ yii\web\Controller::EVENT_BEFORE_ACTION => 'access' ]; } public function access(){ foreach($this->actions as $action){ if($this->owner->action->id == $action){ if (!\Yii::$app->user->can('admin')) { throw new ForbiddenHttpException('Доступ закрыт.'); } } } } }
подключим в нужном контроллере:
public function behaviors() { return [ 'verify' => [ 'class' => 'common\components\rbac\Verify', 'actions' => [ 'about', 'contact' ] ] ]; }
В методе behaviors() контроллера указываем название класса с пространством имен, и в свойстве actions передаем названия свойств по которым будем контролировать доступ.
В нашем классе Verify вешаем выполнение метода access() на событие EVENT_BEFORE_ACTION, которое срабатывает перед выполнением каждого действия контроллера. Подробнее про события можно прочитать тут. Далее в цикле перебираем методы, доступ к которым ограничен и если название совпало с текущим методом - делаем проверку.
Вот и все, пользователи созданы, роли им заданы, далее можно использовать для предоставления доступа вышеприведенными способами, например, к админке сайта на Yii2, отдельным страницам и тд.
Для простого сайта и блога, где достаточно одного админа и регистрация пользователей не нужна - можно не создавать роли, а использовать правила доступа для гостей и авторизованных пользователей ACF, то есть создать одного пользователя который будет админом, а для остальных посетителей сайта просто отключить регистрацию. Подробнее об этом...