Yii2 RBAC DbManager
  • 1612

Yii2 RBAC DbManager - часть 1. Настройка и создание ролей на практике.

Автор: admin | 03 января (Чт.) 2019г. в 21ч.08м.

Вступление в тему.

Контроль доступа на основе ролей RBAC - встроенный функционал в yii2. В данной статье постараюсь на примере блога показать, как пользоваться этим "зверем". В интернете масса материалов по этому поводу, однако хотелось бы построить урок так, чтобы читатель мог применить RBAC на своем проекте сразу, после прочтения данного материала. Для этого я буду освещать данную тему на примере простого блога, чтобы не было лишней логики, но при этом было бы понятно как применить RBAC в yii2 на реальном проекте.

Настройка RBAC в yii2.

Я предварительно установил с помощью composer yii2 advanced шаблон. Этот шаблон будет служить площадкой для обучения. 
В данном уроке буду использовать RBAC DbManager, чтобы хранить данные о ролях в базе данных. Так как rbac уже является частью yii2 и ничего устанавливать не нужно, то нам надо подключить данный компонент в настройках приложения. Но прежде нужно создать базу данных и подключить ее в @common/config/main.local.php :
<?php
return [
    'components' => [
//Тут записываем имя базы, username и password
        'db' => [
            'class' => 'yii\db\Connection',
            'dsn' => 'mysql:host=localhost;dbname=lesson_rbac',
            'username' => 'root',
            'password' => '',
            'charset' => 'utf8',
        ],
        'mailer' => [
            'class' => 'yii\swiftmailer\Mailer',
            'viewPath' => '@common/mail',
            // send all mails to a file by default. You have to set
            // 'useFileTransport' to false and configure a transport
            // for the mailer to send real emails.
            'useFileTransport' => true,
        ],
    ],
];
​

Теперь нам нужно запустить миграции из консоли, перейдя в корень сайта - yii migrate , которые создадут нужные таблицы в базе данных.  Создадутся две таблицы в подключенной базе - user и migration , которые являются самыми базовыми таблицами в yii2. 
yii2 migration в консоли
Созданные таблицы с помощью миграций.
Теперь можно приступить к подключению компонента RBAC в конфигурации сайта. Перейдем в @common/config/main.php и подключим rbac:
//...

'components' => [
        'cache' => [
            'class' => 'yii\caching\FileCache',
        ],
        
        'authManager' => [
            'class' => 'yii\rbac\DbManager',
        ],

//...
        
    ],​

Теперь нужно выполнить миграции уже для построения таблиц для компонента rbac DbManager. В консоли из корня сайта выполняем комманду  yii migrate --migrationPath=@yii/rbac/migrations/

В базе должны создаться еще 4 таблицы:
Таблицы для rbac yii2
Если бы миграции были запущены до того, как в конфигурации был подключен rbac, то в консоли мы получили бы ошибку Exception 'yii\base\InvalidConfigException' with message 'You should configure "authManager" component to use database before executing this migration.'  Поэтому сначала подключаем в конфиге, а потом делаем миграцию.

Базовое создание ролей.

lkТеперь приступим к созданию ролей. начнем с малого и создадим две роли - admin и user. Так как мы только начали разробатывать сайт, то у нас нет рабочей административной части и формы создания ролей и прав. В дальнейшем мы реализуем такую форму, но пока у нас нет веб интерфейса для создания ролей, то для первоначального создания наших ролей создадим консольный контроллер, в котором будут создаваться наши роли и вызовем его из консоли.
Итак, в папке @console/controllers создадим RbacStartController.php (название может быть любое). Вот его содержание:
<?php
namespace console\controllers;

use Yii;
use yii\console\Controller;

class RbacStartController extends Controller
{
    public function actionInit()
    {
        $auth = Yii::$app->authManager;

        // добавляем роль "user"
        $user = $auth->createRole('user');
        $auth->add($user);

        // добавляем роль "admin"
        $admin = $auth->createRole('admin');
        $auth->add($admin);
        $auth->addChild($admin, $user);
   }

}​

Теперь в консоли из корня сайта вызываем консольный контроллер и экшен, который создаст в базе две роли - admin и user:

php yii rbac-start/init

Пусть роль по умолчанию для каждого зарегестрированного пользователя будет user. Для этого при регистрации пользователя будет автоматически прикрепляться роль user.
Создадим данный функционал. Для этого изменим код  метода signup() в модели  SignupForm.

public function signup()
{
    if (!$this->validate()) {
        return null;
    }
    
    $user = new User();
    $user->username = $this->username;
    $user->email = $this->email;
    $user->setPassword($this->password);
    $user->generateAuthKey();

    //Добавляем роль по умолчанию для каждого зарегестрированного
    if($user->save()){
        $auth = Yii::$app->authManager;
        $role = $auth->getRole('user');
        $auth->assign($role, $user->id);

        return $user;
    }
    
    return null;
}

Теперь зарегистрируем пару пользователей на сайте через форму регистрации на сайте, которая имеется в yii2 из коробки. В таблице user должны появиться две учетные записи пользователей. 
Пользователи в базе данных.
Также появились записи в таблице auth_assignment  для данных пользователей:
Rbac yii2 добавление роли в базу данных.
Теперь нам нужно создать возможность присваивать роль admin из консоли, чтобы назначить роль админа для нужного пользователя по id. Поэтому создадим консольный контроллер с реализацией такой возможности:

<?php
namespace console\controllers;

use Yii;
use yii\console\Controller;
use common\models\User;
use yii\console\ExitCode;
use yii\helpers\Console;

//php yii rbac-admin-assign/init 1
class RbacAdminAssignController extends Controller
{
    public function actionInit($id){

        //Проверяем обязательный параметр id
        if(!$id || is_int($id)){
            // throw new \yii\base\InvalidConfigException("param 'id' must be set");
            $this->stdout("Param 'id' must be set!\n", Console::BG_RED);
            return ExitCode::UNSPECIFIED_ERROR;
        }

        //Есть ли пользователь с таким id
        $user = (new User())->findIdentity($id);
        if(!$user){
            // throw new \yii\base\InvalidConfigException("User witch id:'$id' is not found");
            $this->stdout("User witch id:'$id' is not found!\n", Console::BG_RED);
            return ExitCode::UNSPECIFIED_ERROR;
        }

        //Получаем объект yii\rbac\DbManager, который назначили в конфиге для компонента authManager
        $auth = Yii::$app->authManager;

        //Получаем объект роли
        $role = $auth->getRole('admin');

        //Удаляем все роли пользователя
        $auth->revokeAll($id);

        //Присваиваем роль админа по id
        $auth->assign($role, $id);

        //Выводим сообщение об успехе и возвращаем соответствующий код
        $this->stdout("Done!\n", Console::BOLD);
        return ExitCode::OK;
        
   }
}

Теперь для того, чтобы дать роль админа, нужно в консоли выполнить комманду:

php yii rbac-admin-assign/init 1

Так, пользователь с id=1 получил роль admin . Для того, чтобы в этом убедиться, посмотрим в базу данных в таблицу auth_assignment:
Таблица auth_assignment

Как проверять роли в rbac.

Итак, теперь на сайте есть два пользователя - админ и юзер. Теперь рассмотрим методы контроля и использования ролей на сайте.
<?php
//Если текущий пользователь - не гость
if (!Yii::$app->user->isGuest) {
    $userId = \Yii::$app->user->getId();

    //Все роли текущего пользователя
    var_dump(\Yii::$app->authManager->getRolesByUser($userId));
    PHP_EOL;

    //Разрешение пользователя
    var_dump(\Yii::$app->authManager->getAssignment('admin', $userId));
    PHP_EOL;

    //Все разрешения пользователя
    var_dump(\Yii::$app->authManager->getAssignments($userId));
    PHP_EOL;

    //Проверка доступа пользователя
    var_dump(\Yii::$app->authManager->checkAccess($userId, 'admin', $params = []));
    PHP_EOL;
    
    //Тоже проверка доступа пользователя
    var_dump(Yii::$app->user->can('admin'));


} else {
    echo "Здравствуйте, Гость!";
}
?>​

Для того, чтобы посмотреть, что вернет данный код - зайдем на сайт под пользователем, которому назначена роль админа:
Методы проверки доступа rbac yii2
Как видите из скриншота, для простой проверки на наличие роли у пользователя можно воспользоваться таким кодом:

if(Yii::$app->user->can('admin')){
    echo "Привет, админ!" . PHP_EOL;
}

//Аналогично работает с вариантом выше
if(\Yii::$app->authManager->checkAccess($userId, 'admin', $params = [])){
    echo "Привет, админ!" . PHP_EOL;
}

С помощью такого условия можно, например показывать разный контент для разных ролей пользователей. Но что если нужно ограничить доступ к целым экшкнам контроллеров для разных пользователей. Рассмотрим иакой вариант.

Как контролировать доступ по ролям в контроллере с фильтром AccessControl.

В контроллере есть возможность с помощью yii\filters\AccessControl разграничить права доступа к разным экшенам. Например, после установки yii2 в контроллере SiteController уже есть код фильтра доступа, но для двух ролей - гостя и зарегестрированного пользователя:
public function behaviors()
{
    return [
        'access' => [
            'class' => AccessControl::className(),
            'only' => ['logout', 'signup'],
            'rules' => [
                [
                    'actions' => ['signup'],
                    'allow' => true,
                    'roles' => ['?'],
                ],
                [
                    'actions' => ['logout'],
                    'allow' => true,
                    'roles' => ['@'],
                ],
                
            ],

        ],
        'verbs' => [
            'class' => VerbFilter::className(),
            'actions' => [
                'logout' => ['post'],
            ],
        ],
    ];
}

Так как у нас есть теперь роли на основе RBAC, то добавим проверку, чтобы к экшену index имел доступ только admin:

public function behaviors()
{
    return [
        'access' => [
            'class' => AccessControl::className(),
            'only' => ['logout', 'signup'],
            'rules' => [
                [
                    'actions' => ['signup'],
                    'allow' => true,
                    'roles' => ['?'],
                ],
                [
                    'actions' => ['logout'],
                    'allow' => true,
                    'roles' => ['@'],
                ],
                
            ],

        ],

        //Доступ только для админа 
        [
            'class' => AccessControl::className(),
            'only' => ['index'],
            'rules' => [
                [
                    'actions' => ['index'],
                    'allow' => true,
                    'roles' => ['admin'],
                ],
            ],
            
        ],
  
        'verbs' => [
            'class' => VerbFilter::className(),
            'actions' => [
                'logout' => ['post'],
            ],
        ],
    ];
}
Теперь, для всех, кроме пользователя с ролью admin вход на указанную страницу закрыт и при попытке зайти на http://localhost/lessons/yii2-rbac-forlesson/frontend/web/index.php?r=site%2Findex нас перебросит на форму входа.

В данном уроке я показал как можно быстро начать работу с RBAC в Yii2. В следующей статье по rbac я подробнее покажу, как работать с разрешениями и правилами в rbac. Продолжение тут.

Читайте также из этой серии:

Приветствую!

Меня зовут Сергей. Я - автор этого блога.

Если Вам был полезен материал на моем сайте, поддержите пожалуйста мой проект, чтобы о нем узнали другие люди - кликните plizz :) на иконку в соц. сети, чтобы поделиться материалом с другими.