Сервис на Yii2: Добавление RBAC для разграничения прав

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

Предыдущие части | Исходники на GitHub

Сейчас наша панель управления закрыта на примитивном уровне только от незалогиненных пользователей:

namespace app\modules\admin;
 
use yii\filters\AccessControl;
 
class Module extends \yii\base\Module
{
    ...
 
    public function behaviors()
    {
        return [
            'access' => [
                'class' => AccessControl::className(),
                'rules' => [
                    [
                        'allow' => true,
                        'roles' => ['@'],
                    ],
                ],
            ],
        ];
    }
 
    ...
}

Но нам нужно будет сделать так, чтобы он был доступен только администраторам.

Как мы уже рассматривали в вебинаре по RBAC, в Yii2 имеется два встроенных менеджера по управлению ролями и привязке их к пользователю. Это PhpManager, хранящий данные в виде массивов в файлах, и DbManager, сохраняющий всё в таблицах в базе данных. Мы подробно обсудили плюсы и минусы каждого подхода в том видео, поэтому здесь теории будет не очень много. Рассмотрим практику внедрения RBAC в проект.

В любом случае, достаточно подключить любой из них как компонент authManager в конфигурационном файле:

'components' => [
    ...
    'authManager' => [
        'class' => 'yii\rbac\PhpManager',
    ],
],

и его методами вроде таких:

$auth = Yii::$app->authManager;
$user = $auth->createRole('user');
$user->description = 'User';
$auth->add($user);
 
$admin = $auth->createRole('admin');
$admin->description = 'Admin';
$auth->add($admin);
 
$auth->addChild($admin, $user);

создавать роли и методом $auth->assign($role, $userId) привязывать роль к пользователю. А сам менеджер уже будет сохранять эту информацию в своих файлах или таблицах.

Для нашего случая нужны всего две роли user и admin. Можно создать только их и проверять доступ по этим ролям. Но более гибкий и предпочтительный вариант – это использование так называемых «разрешений» вроде adminPanel и подобных и привязка их к ролям.

Использование имён разрешений вроде adminPanel в модулях предпочтительнее имён ролей вроде user или admin, так как на каждом сайте можно будет делать разных админов и пользователей, в любой последовательности привязывая к ним ваши разрешения.

Чтобы не создавать всё вручную, можно создать консольный контроллер, в действии которого производить всё построение ролей и разрешений:

namespace app\commands;
 
use Yii;
use yii\console\Controller;
 
/**
 * RBAC generator
 */
class RbacController extends Controller
{
    /**
     * Generates roles
     */
    public function actionInit()
    {
        $auth = Yii::$app->getAuthManager();
        $auth->removeAll();
 
        $adminPanel = $auth->createPermission('adminPanel');
        $adminPanel->description = 'Admin panel';
        $auth->add($adminPanel);
 
        $user = $auth->createRole('user');
        $user->description = 'User';
        $auth->add($user);
 
        $admin = $auth->createRole('admin');
        $admin->description = 'Admin';
        $auth->add($admin);
 
        $auth->addChild($admin, $user);
        $auth->addChild($admin, $adminPanel);
 
        $this->stdout('Done!' . PHP_EOL);
    }
}

Здесь мы создаём роли user и admin, для простоты наследуем admin от user (чтобы администратор мог делать всё, что позволено пользователю). Также создаём разрешение adminPanel, по которому будем проверять доступ в панель управления, и присваиваем это разрешение только роли admin.

Может показаться более логичным поместить работу с RBAC в модуль user, но разрешения и роли обычно оказываются раскиданными по всему проекту. Поэтому удобнее оставить в модулях только их специфичные разрешения, а создание ролей оставить на уровне самого приложения.

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

Сейчас у нас есть всего одно разрешение, относящееся к модулю admin. А мы договорились, что всё, что относится к конкретному модулю мы будем помещать в его директорию. Так что создадим в модуле папку rbac и создадим там класс с константой:

namespace app\modules\admin\rbac;
 
class Rbac
{
    const PERMISSION_ADMIN_PANEL = 'permAdminPanel';
}

Не стоит бояться длинных наименований, так как автоподстановка в любой IDE сразу покажет весь список.

Теперь впишем наше значение в фильтр модуля:

namespace app\modules\admin;
 
use app\modules\admin\rbac\Rbac as AdminRbac;
use yii\filters\AccessControl;
use Yii;
 
class Module extends \yii\base\Module
{
    ...
 
    public function behaviors()
    {
        return [
            'access' => [
                'class' => AccessControl::className(),
                'rules' => [
                    [
                        'allow' => true,
                        'roles' => [Rbac::PERMISSION_ADMIN_PANEL],
                    ],
                ],
            ],
        ];
    }
 
    ...
}

Также в пункт главного меню в views/layouts/main.php:

use app\modules\admin\rbac\Rbac as AdminRbac;
...
echo Nav::widget([
    'options' => ['class' => 'navbar-nav navbar-right'],
    'activateParents' => true,
    'items' => array_filter([
        ['label' => Yii::t('app', 'NAV_HOME'), 'url' => ['/main/default/index']],
        ...
        Yii::$app->user->can(AdminRbac::PERMISSION_ADMIN_PANEL) ?
            ['label' => Yii::t('app', 'NAV_ADMIN'), 'url' => ['/admin/default/index']] :
            false,
        ...
    ]),
]);
NavBar::end();

и в наш консольный контроллер:

use app\modules\admin\rbac\Rbac as AdminRbac;
...
class RbacController extends Controller
{
    /**
     * Generates roles
     */
    public function actionInit()
    {
        $auth = Yii::$app->getAuthManager();
        $auth->removeAll();
 
        $adminPanel = $auth->createPermission(AdminRbac::PERMISSION_ADMIN_PANEL);
        $adminPanel->description = 'Admin panel';
        $auth->add($adminPanel);
 
        $user = $auth->createRole('user');
        $user->description = 'User';
        $auth->add($user);
 
        $admin = $auth->createRole('admin');
        $admin->description = 'Admin';
        $auth->add($admin);
 
        $auth->addChild($admin, $user);
        $auth->addChild($admin, $adminPanel);
 
        $this->stdout('Done!' . PHP_EOL);
    }
}

Одно из достоинств наличия класса-справочника с константами – возможность быстро просмотреть весь список в одном месте. Не нужно каждый раз искать по контроллерам и представлениям какие же правила имеются в данном модуле. Да и можно спокойно переименовать константу средствами самой IDE, и во всём проекте она переименуется автоматически.

Роли и разрешения готовы. Теперь их надо как-то присвоить пользователям. Сделаем для этого ещё один консольный контроллер:

namespace app\commands;
 
use app\modules\user\models\User;
use Yii;
use yii\console\Controller;
use yii\console\Exception;
use yii\helpers\ArrayHelper;
 
/**
 * Interactive console roles manager
 */
class RolesController extends Controller
{
    /**
     * Adds role to user
     */
    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);
    }
 
    /**
     * Removes role from user
     */
    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);
    }
 
    /**
     * @param string $username
     * @throws \yii\console\Exception
     * @return User the loaded model
     */
    private function findModel($username)
    {
        if (!$model = User::findOne(['username' => $username])) {
            throw new Exception('User is not found');
        }
        return $model;
    }
}

Теперь запустим действие привязки роли:

php yii roles/assign

Он попросит нас ввести логин пользователя и роль.

После этого можно увидеть, что всё у нас попало в assignments.php:

return [
    1 => [
        'admin',
    ],
];

Пользователю с ID=1 присвоилась роль admin.

Если подключить аналогично DbManager, применить его миграции, выполнить php yii rbac/init и привязать аналогично роль к пользователю, то это всё появится в соответствующих таблицах в базе данных.

Для любого сайта достаточно выбрать PhpManager или DbManager и использовать его. Это стандартная практика, применимая повсюду. Если же хочется рассмотреть другие альтернативы, то об одной из них поговорим в этой статье.

Но при использовании DbManager нам не особо хочется дёргать каждый раз базу данных для перебора ролей и разрешений.

Менеджер PhpManager удобен высокой производительностью, так как он загружает все роли одним запросом к своим файлам вместо рекурсивных запросов к базе данных. Но при большом числе пользователей файл assignments.php станет большим и неповоротливым.

Мы можем пойти альтернативным путём, храня привязку к роли прямо в поле role модели User и используя подход с ролями по умолчанию defaultRoles и распределением ролей общим правилом GroupRule. Но это «костыль», так как с ним не будут работать getRolesByUser(), assign() и прочие системные методы.

Вместо этого можно схитрить, как мы и говорили в вебинаре. А именно, оставить все роли в файлах, а хранение роли поместить в поле role в модели пользователя и доработать PhpManager на получение роли из этого поля (вместо файла assignments.php). Всё равно по стандартам чистого RBAC пользователю не нужно присваивать несколько ролей.

Итак, создадим миграцию, добавляющую поле role и заполняющее его ролью user:

use yii\db\Migration;
 
class m160310_085103_add_user_role_field extends Migration
{
    public function up()
    {
        $this->addColumn('{{%user}}', 'role', $this->string(64));
 
        $this->update('{{%user}}', ['role' => 'user']);
    }
 
    public function down()
    {
        $this->dropColumn('{{%user}}', 'role');
    }
}

Теперь напишем свой гибридный AuthManager. В Yii2 менеджер монолитен, так что просто поменять хранилище ролей и привязок к пользователю мы не сможем. Вместо этого поправим функциональность самого PhpManager.

Отнаследуемся от класса yii\rbac\PhpManager и переопределим те методы, которые работают с его полем $this->_assignments. В них будем напрямую обращаться к нашей модели, а не брать значения, полученные из файла assignments.php. В примитивном случае для определения роли нужно переопределить только метод getAssignments, так как в методе checkAccess вызывается именно он. В итоге достаточно такого переопределения:

namespace app\components;
 
use app\modules\user\models\User;
use yii\rbac\Assignment;
use yii\rbac\PhpManager;
use Yii;
 
class AuthManager extends PhpManager
{
    public function getAssignments($userId)
    {
        if ($userId && $user = $this->getUser($userId)) {
            $assignment = new Assignment();
            $assignment->userId = $userId;
            $assignment->roleName = $user->role;
            return [$assignment->roleName => $assignment];
        }
        return [];
    }
 
    /**
     * @param integer $userId
     * @return null|\yii\web\IdentityInterface|User
     */
    private function getUser($userId)
    {
        $webUser = Yii::$app->get('user', false);
        if ($webUser && !$webUser->getIsGuest() && $webUser->getId() == $userId) {
            return $webUser->getIdentity();
        } else {
            return User::findOne($userId);
        }
    }
}

Но такой менеджер слишком примитивен. Его можно использовать только для чтения ролей, а не для их изменения. Для большей совместимости с оригинальным классом переопределим и методы вроде assign и revoke:

namespace app\components;
 
use app\modules\user\models\User;
use yii\rbac\Assignment;
use yii\rbac\PhpManager;
use Yii;
 
class AuthManager extends PhpManager
{
    public function getAssignments($userId)
    {
        if ($userId && $user = $this->getUser($userId)) {
            $assignment = new Assignment();
            $assignment->userId = $userId;
            $assignment->roleName = $user->role;
            return [$assignment->roleName => $assignment];
        }
        return [];
    }
 
    public function getAssignment($roleName, $userId)
    {
        if ($userId && $user = $this->getUser($userId)) {
            if ($user->role == $roleName) {
                $assignment = new Assignment();
                $assignment->userId = $userId;
                $assignment->roleName = $user->role;
                return $assignment;
            }
        }
        return null;
    }
 
    public function getUserIdsByRole($roleName)
    {
        return User::find()->where(['role' => $roleName])->select('id')->column();
    }
 
    public function assign($role, $userId)
    {
        if ($userId && $user = $this->getUser($userId)) {
            $assignment = new Assignment([
                'userId' => $userId,
                'roleName' => $role->name,
                'createdAt' => time(),
            ]);
            $this->setRole($user, $role->name);
            return $assignment;
        }
        return null;
    }
 
    public function revoke($role, $userId)
    {
        if ($userId && $user = $this->getUser($userId)) {
            if ($user->role == $role->name) {
                $this->setRole($user, null);
                return true;
            }
        }
        return false;
    }
 
    public function revokeAll($userId)
    {
        if ($userId && $user = $this->getUser($userId)) {
            $this->setRole($user, null);
            return true;
        }
        return false;
    }
 
    /**
     * @param integer $userId
     * @return null|\yii\web\IdentityInterface|User
     */
    private function getUser($userId)
    {
        $webUser = Yii::$app->get('user', false);
        if ($webUser && !$webUser->getIsGuest() && $webUser->getId() == $userId) {
            return $webUser->getIdentity();
        } else {
            return User::findOne($userId);
        }
    }
 
    /**
     * @param User $user
     * @param string $roleName
     */
    private function setRole(User $user, $roleName)
    {
        $user->role = $roleName;
        $user->updateAttributes(['role' => $roleName]);
    }
}

В конфигурационном файле config/common.php поменяем теперь оригинальный PhpManager на свой:

'components' => [
    ...
    'authManager' => [
        'class' => 'app\components\AuthManager',
    ],
],

Теперь можно попробовать перегенерировать роли:

php yii rbac/init

и заново попробовать привязать их к пользователям:

php yii roles/assign

При этом файл assignments.php должен остаться пустым, а поле role в таблице user в базе заполниться новой ролью.

Хранение ролей мы организовали и поле role в таблицу добавили. Осталось добавить вывод и установку роли в админку.

Управление ролями

Для отображения роли и присваивания её при управлении пользователями добавим правила валидации и надпись для поля role в модель User:

namespace app\modules\user\models;
...
class User extends ActiveRecord implements IdentityInterface
{
    ...
 
    public function rules()
    {
        return [
            ...
            ['role', 'string', 'max' => 64],
        ];
    }
 
    public function attributeLabels()
    {
        return [
            ...
            'role' => Module::t('module', 'USER_ROLE'),
        ];
    }
}

И в модели backend\User добавим это поле в сценарии валидации:

namespace app\modules\user\models\backend;
...
class User extends \app\modules\user\models\User
{
    ...
 
    public function scenarios()
    {
        $scenarios = parent::scenarios();
        $scenarios[self::SCENARIO_ADMIN_CREATE] = ['username', 'email', 'status', 'role', 'newPassword', 'newPasswordRepeat'];
        $scenarios[self::SCENARIO_ADMIN_UPDATE] = ['username', 'email', 'status', 'role', 'newPassword', 'newPasswordRepeat'];
        return $scenarios;
    }
}

Аналогично добавим новое поле в поисковую модель backend\search\UserSearch:

$query->andFilterWhere([
    'id' => $this->id,
    'status' => $this->status,
    'role' => $this->role,
]);

И в форму в представлении modules/user/views/backend/_form.php добавим выпадающий список ролей:

<?php
<div class="user-form">
 
    <?php $form = ActiveForm::begin(); ?>
 
    <?= $form->field($model, 'username')->textInput(['maxlength' => true]) ?>
 
    ...
 
    <?= $form->field($model, 'status')->dropDownList(User::getStatusesArray()) ?>
 
    <?= $form->field($model, 'role')->dropDownList(ArrayHelper::map(Yii::$app->authManager->getRoles(), 'name', 'description')) ?>
 
    ...
 
    <?php ActiveForm::end(); ?>
 
</div>

В Yii нет построителя форм, в который можно было бы спрятать такие повороты судьбы с дёрганием authManager из представления. Если бы мы использовали отдельную модель для формы, то бы тоже могли спрятать это туда. Чтобы это не выглядело так кощунственно, лучше передать массив для выпадающего списка из контроллера:

<?php
<?= $form->field($model, 'role')->dropDownList($rolesList) ?>

или даже сочинить свой InputWidget. Ну это сейчас не так важно.

Здесь мы могли бы последовать принципам профессиональной разработки и переписать модуль user, но управление пользователями – это не главная часть нашего приложения. Выделением слоя предметной области, отделением его от слоя отображения и продумыванием архитектуры мы займёмся в основном модуле проектов. А здесь вместо настоящих моделей оставим стандартные классы ActiveRecord и обычный CRUD.

Теперь нам нужно вывести роль в GridView. Для этого сделаем колонку, которая будет отображать описание роли, выделяя привилегированных пользователей красными бейджиками:

namespace app\modules\user\widgets\backend\grid;
 
use yii\grid\DataColumn;
use yii\helpers\Html;
use Yii;
 
class RoleColumn extends DataColumn
{
    public $defaultRole = 'user';
 
    protected function renderDataCellContent($model, $key, $index)
    {
        $value = $this->getDataCellValue($model, $key, $index);
        $label = $value ? $this->getRoleLabel($value) : $value;
        $class = $value == $this->defaultRole ? 'primary' : 'danger';
        $html = Html::tag('span', Html::encode($label), ['class' => 'label label-' . $class]);
        return $value === null ? $this->grid->emptyCell : $html;
    }
 
    private function getRoleLabel($roleName)
    {
        if ($role = Yii::$app->authManager->getRole($roleName)) {
            return $role->description;
        } else {
            return $roleName;
        }
    }
}

И подключим эту колонку в наш modules/user/views/backend/index.php:

<?php
<?= GridView::widget([
    'dataProvider' => $dataProvider,
    'filterModel' => $searchModel,
    'columns' => [
        'id',
        ...
        [
            'class' => LinkColumn::className(),
            'attribute' => 'username',
        ],
        'email:email',
        ...
        [
            'class' => RoleColumn::className(),
            'filter' => ArrayHelper::map(Yii::$app->authManager->getRoles(), 'name', 'description'),
            'attribute' => 'role',
        ],
 
        ['class' => ActionColumn::className()],
    ],
]); ?>

Чтобы видеть все присвоенные роли:

Теперь дополним фронтенд.

Доработка формы регистрации

Дополним наш модуль новым параметром $defaultRole:

namespace app\modules\user;
 
use Yii;
 
class Module extends \yii\base\Module
{
    /**
     * @var string
     */
    public $defaultRole = 'user';
    /**
     * @var int
     */
    public $emailConfirmTokenExpire = 259200; // 3 days
    /**
     * @var int
     */
    public $passwordResetTokenExpire = 3600;
 
    public static function t($category, $message, $params = [], $language = null)
    {
        return Yii::t('modules/user/' . $category, $message, $params, $language);
    }
}

В саму форму регистрации добавим поле $_defaultRole, которое будем передавать в конструктор и присваивать пользователю:

namespace app\modules\user\models\frontend\form;
 
use app\modules\user\models\User;
use app\modules\user\Module;
use yii\base\Model;
use Yii;
 
/**
 * Signup form
 */
class SignupForm extends Model
{
    public $username;
    public $email;
    public $password;
    public $verifyCode;
 
    private $_defaultRole;
 
    public function __construct($defaultRole, $config = [])
    {
        $this->_defaultRole = $defaultRole;
        parent::__construct($config);
    }
 
    ...
 
    public function signup()
    {
        if ($this->validate()) {
            $user = new User();
            $user->username = $this->username;
            $user->email = $this->email;
            $user->setPassword($this->password);
            $user->status = User::STATUS_WAIT;
            $user->role = $this->_defaultRole;
            $user->generateAuthKey();
            $user->generateEmailConfirmToken();
            ...
            return $user;
        }
 
        return null;
    }
}

И в контроллере будем передавать в форму этот параметр через конструктор:

namespace app\modules\user\controllers\frontend;
 
...
 
class DefaultController extends Controller
{
    ...
    public function actionSignup()
    {
        $model = new SignupForm($this->module->defaultRole);
        if ($model->load(Yii::$app->request->post())) {
            if ($user = $model->signup()) {
                Yii::$app->getSession()->setFlash('success', Module::t('module', 'FLASH_EMAIL_CONFIRM_REQUEST'));
                return $this->goHome();
            }
        }
 
        return $this->render('signup', [
            'model' => $model,
        ]);
    }
}

На этом с ролями пока всё.

Мы добавили к проекту поддержку ролей и разрешений. При этом мы сделали собственный «гибридный» вариант хранения ролей, скрестив PhpManager с полем role в таблице модели. При этом все стандартные методы вроде assign, revoke и getRolesByUser остались полностью рабочими.

В следующей части подготовим этот компонент для совместного использования в других проектах, научившись выкладыввть свои расширения на GitHub и публиковать их как пакеты Composer:

Публикация расширений на GitHub и Packagist

Не забудьте подписаться на рассылку статей в сайдбаре или вместе с нами записаться и «позажигать» на бесплатных вебинарах. До встречи!

Комментарии

 

LAV45
class AuthManager extends PhpManager { ... }

> Но такой менеджер слишком примитивен.

Это не менеджер, а вы просто не туда затащили функционал по добавлению/редактирования пользовательских ролей.

Добавьте User setRole и getRole и AuthManager уже не будет казаться таким примитивеным.

class User extends ActiveRecord implements IdentityInterface
{
...
    public function setRole($name)
    {
        $auth = Yii::$app->authManager;

        if (!empty($name)) {
            $userRoles = array_keys($auth->getRolesByUser($this->id));
            if (!isset($userRoles[0]) || $userRoles[0] != $name) {
                $role = $auth->getRole($name);
                $event = $this->getIsNewRecord() ? self::EVENT_AFTER_INSERT : self::EVENT_AFTER_UPDATE;

                $this->on($event, function () use ($auth, $role) {
                    $auth->revokeAll($this->id);
                    $auth->assign($role, $this->id);
                });
            }
        } elseif ($this->getIsNewRecord() === false) {
            $auth->revokeAll($this->id);
        }
    }

    public function getRole()
    {
        $auth = Yii::$app->authManager;
        $roles = $auth->getRolesByUser($this->id);
        return !empty($roles) ? array_keys($roles)[0] : null;
    }

    public static function getRoleList()
    {
        $data = Yii::$app->authManager->getRoles();
        $roles = ArrayHelper::getColumn($data, 'description');
        return $roles;
    }
}
Ответить

 

Дмитрий Елисеев

И как это относится к избавлению от хранения assignments?

Ответить

 

lav45

Вам ненужно избавляться от хранения assignments.
Этот метод поможет вам избавится от переопределения класса PhpManager, и исользовать стандактный authManager с произвольными настройками. Пускай разраюотчик решает использовать ему DbManager или PhpManager.
Нет необходимости добавлять User поле role т.к. эта информация будет хранится в Yii::$app->authManager->getRolesByUser($user_id).

Ответить

 

Дмитрий Елисеев

Да, обычно так и вывожу через getRolesByUser($id), если использую стандартные менеджеры.

Здесь аналогично разработчик может использовать (или нет) любой свой менеджер, подписавшись на события модели и реализовать такой же assign() в своём обработчике.

Ответить

 

Гераклит Вяткин

Если я, например, использую DbManager и вывожу роли в GridView, то у меня для каждого пользователя на странице GridView будет отдельный запрос чтобы выяснить какие у него есть роли?

Ответить

 

Дмитрий Елисеев

Да.

Ответить

 

Дмитрий Кривошеин

Как всегда отличный материал!!! Спасибо Дима за твой труд!

Ответить

 

Andrey

Отличная статья!

Ответить

 

Олег

Дмитрий, ошибка у Вас :-)

$ yii roles/assign
Username: admin
Role: [user,admin,?]: admin
Error: Getting unknown property: yii\console\Application::user
Ответить

 

Дмитрий Елисеев

Исправил.

Ответить

 

Олег

Пару мелочей по модулю user.

'BUTTON_SEND' => 'Send',
'BUTTON_SEND' => 'Отправить',

views/frontend/default/passwordReset.php

<?= Html::submitButton(Module::t('module', 'BUTTON_SAVE'), ['class' => 'btn btn-primary', 'name' => 'reset-button']) ?>

P.S:. Лень кидать pull request'ы.

Ответить

 

Дмитрий Елисеев

Спасибо! Исправил.

Ответить

 

... – muzon.ws

Спасибо, отличный материал!

Ответить

 

Николай Куропятников

Как привязать роль к не авторизованному гостю? Чтобы в RBAC была роль Гость.

Ответить

 

Дмитрий Елисеев

Добавить роль guest и прописать её в defaultRoles.

Ответить

 

Anton Gubarev

Дмитрий поясните пожалуйста по Module::t(). Не нашел нигде описания это возможности. В документации только Yii::t()

Ответить

 

Дмитрий Елисеев
Ответить

 

Anton Gubarev

Спасибо!

Ответить

 

Михаил

Здравствуйте, скажите а есть ли простой способ использовать RBAC вместе с activeDataProvider?
Проверять, что пользователь может читать статью которая выбирается.

Ответить

 

Дмитрий Елисеев

А в чём именно проблема?

Ответить

 

Михаил

В данном случае не ясно как это будет выглядеть в принципе.
Мы имеем методы can у user, мы имеем папку с правами RBAC, где лежат правила.
Затем есть контроллер который допустим выводит новости.
Все как мы можем использовать rbac это вызвать Yii::$app->user->can, как при этом заставить activeDataProvider фильтровать данные - не понятно.

Приложение это REST Full API.
Если вы знаете статью на эту тему, буду признателен.
Спасибо)

Ответить

 

Дмитрий Елисеев

Для выборок фильтруем хардкорно:

Post::find()->andWhere(['user_id' => Yii::$app->user->id])
Ответить

 

Иван Зайцев

Решил пропустить все, что связано с тестированием, и теперь пожалел... в какой-то момент понял, что у меня не выполняется действие logout модуля user:

Method Not Allowed. This url can only handle the following request methods: POST.

в виджете меню все прописано:

'url' => ['/user/default/logout'],
'linkOptions' => ['data-method' => 'post']]

А если закомментировать в контроллере:

'actions' => [
    // 'logout' => ['post'],
],

то logout начинает работать. Зачем вообще отправлять этот Url методом post?
И так и не могу понять, почему перестало работать...

Ответить

 

Дмитрий Елисеев

> Зачем вообще отправлять этот Url методом post?

Все что-то производящие операции вроде delete для безопасности (и для защиты от кеширования) делают через POST. А иначе кто-то впишет такую "картинку" или ссылку:

<img src="/admin/user/delete/1" />
<a href="/admin/user/delete/1">здесь</a>

и у администратора этот адрес сработает и в пользователя нечаянно удалит. Аналогично /logout сделано работающим только через POST.

Если вдруг перестало работать после обновления фреймворка, то очистите папку web/assets и обновите страницу.

Ответить

 

Иван Зайцев

> Все что-то производящие операции вроде delete для безопасности делают через POST
Спасибо за пояснение)

Очистил папку web/assets (оставил в ней только .gitignore), не помогло...
Заметил, что в модуле admin при нажатии на /logout, действие выполняется.
а в модуле main тот же самый /logout не выполняется.
Описаны они одинаково. пока ищу причину.

Ответить

 

Иван Зайцев

Все, решил проблему, дело было в закомментированном фрагменте:

public $depends = [
    //'yii\web\YiiAsset',
    //'yii\bootstrap\BootstrapAsset',
];

раскомментировал подключение 'yii\web\YiiAsset' и все заработало
а если раскомментировать строку 'yii\bootstrap\BootstrapAsset' то возникает проблема в верскте, конфликты в css файлах

Ответить

 

SerF SerF

Странно, все сделал как написано
не сохраняются childs и assignments, ни в базе, ни в файлах
отсюда не работает Yii::$app->user->can(AdminRbac::PERMISSION_ADMIN_PANEL

Ответить

 

HiStO rIaN

да не читай ты этого дауна, он ноль в программировании

Ответить

 

Sergey Aver

Куда мне нужно копать если не работает команда

php yii migrate --migrationPath=@yii/rbac/migrations/

Вернее она обрабатывается, в таблицу миграций записывается запись, но вот сами таблицы rbac не добавляются

Ответить

 

Дмитрий Елисеев

Весьма странно. С таким не сталкивался.

Ответить

 

андрей

Sergey Aver В нормальную человеческую БД phpmyadmin и не тратить на этот мусор миграционный ни секунды

Ответить

 

Роман

Здрвствуйте.
Запускаю команду

php yii roles/assign

валятся ошибки:

Exception 'yii\base\InvalidConfigException' with message 'Unknown bootstrapping

in Z:\Programs\Sites\yii2-basic-elisdn\www\vendor\yiisoft\yii2\base\Application.

Stack trace:
#0 Z:\Programs\Sites\yii2-basic-elisdn\www\vendor\yiisoft\yii2\base\Application.
#1 Z:\Programs\Sites\yii2-basic-elisdn\www\vendor\yiisoft\yii2\console\Applicati
#2 Z:\Programs\Sites\yii2-basic-elisdn\www\vendor\yiisoft\yii2\base\Object.php(1
#3 Z:\Programs\Sites\yii2-basic-elisdn\www\vendor\yiisoft\yii2\base\Application.
#4 Z:\Programs\Sites\yii2-basic-elisdn\www\vendor\yiisoft\yii2\console\Applicati
#5 Z:\Programs\Sites\yii2-basic-elisdn\www\yii(28): yii\console\Application->__c
#6 {main}

Попробовал запустить

php yii

- тоже самое.
Видимо где-то в конфиге ошибка закралась?
Где смотреть?

Ответить

 

Дмитрий Елисеев

Смотреть в полном тексте ошибки 'Unknown bootstrapping...'.

Ответить

 

Роман

Извиняюсь, Шторм урезает почему-то.

Вот такой полный текст ошибок:

Exception 'yii\base\InvalidConfigException' with message 'Unknown bootstrapping component ID: gii'

in Z:\Programs\Sites\yii2-basic-elisdn\www\vendor\yiisoft\yii2\base\Application.php:306

Stack trace:
#0 vendor\yiisoft\yii2\base\Application.php(267): yii\base\Application->bootstrap()
#1 vendor\yiisoft\yii2\console\Application.php(120): yii\base\Application->init()
#2 vendor\yiisoft\yii2\base\Object.php(107): yii\console\Application->init()
#3 vendor\yiisoft\yii2\base\Application.php(206): yii\base\Object->__construct(Array)
#4 vendor\yiisoft\yii2\console\Application.php(85): yii\base\Application->__construct(Array)
#5 yii(28): yii\console\Application->__construct(Array)
#6 {main}
Ответить

 

Дмитрий Елисеев

В секции 'bootstrap' => ['log', 'gii'] в config/console.php удалите 'gii'.

Ответить

 

Роман

Дмитрий, спасибо.
Удалил.

Теперь при попытке выполнить

php yii roles/assign

при вводе имени пользователя валятся ошибки:

Z:\Programs\Sites\yii2-basic-elisdn\www>php yii roles/assign
Username: admin
PHP Fatal error:  Call to a member function getRoles() on null in commands\RolesController.php on line 29
...

Скорее всего из-за неуказанного в config/components.php:

'authManager' => [
    'class' => 'yii\rbac\PhpManager',
],

Ok, указываю.

Но после этого шаг указания роли в консоли зацикливается:

Z:\Programs\Sites\yii2-basic-elisdn\www>php yii roles/assign
Username: admin
Role: [,?]: admin
Role: [,?]: anything else?
Role: [,?]:

Что я мог упустить?

Ответить

 

Дмитрий Елисеев

Роли не создали.

Ответить

 

Роман

Так ведь роли были созданы в app\commands\RbacController.php

Всего две: user и admin.

Соответственно, ввожу вторым шагом роль admin или user.
В ответ повторный запрос.
И так без конца.

Ничего уже не понимаю.

Где в таком случае необходимо роли создавать?

Ответить

 

Дмитрий Елисеев

Тогда бы выводилось:

Role: [user,admin,?]:
Ответить

 

Роман

В общем, создал в корне приложения папку rbac.
В ней файлы assignments, items и rules.
В items прописал роли.
Всё заработало.

В статье не было указано.
Статью изучаю без каких-либо дополнительных знаний.
Буду курить эдишынали.

Ответить

 

Дмитрий Елисеев

> В статье не было указано.

После создания в RbacController его нужно запустить.

> Статью изучаю без каких-либо дополнительных знаний.

А смысл?

Ответить

 

Алексей – zlaksudbi.ru

Действительно, в статье не указано, что после создания RbacController необходимо в рукопашную создать rbac/items.php. Мы, новички, на этом здорово спотыкаемся )

Ответить

 

Дмитрий Елисеев

Не в рукопашную создать, а этот контроллер как yii rbac/init запустить.

Ответить

 

Алексей – zlaksudbi.ru

Я так и запускал, в ответ получал ругательство:
PHP Warning 'yii\base\ErrorException' with message 'Invalid argument supplied for foreach()'

А когда в ручную создал, тогда всё заработало.

Ответить

 

oleg

Добрый день у меня вылетает ошибка.

# php yii rbac/init
Exception 'Error' with message 'Call to a member function createPermission() on null'

in /basic/commands/RbacController.php:21
Ответить

 

Дмитрий Елисеев

Настройте 'authManager' в config/console.php.

Ответить

 

oleg

Спасибо за ответ но теперь вылетает

php yii rbac/init
PHP Warning 'yii\base\ErrorException' with message 'Invalid argument supplied for foreach()'

in basic/vendor/yiisoft/yii2/rbac/PhpManager.php:646

Stack trace:
#0 basic/vendor/yiisoft/yii2/rbac/PhpManager.php(646): yii\base\ErrorHandler->handleError(2, 'Invalid argumen...', '/home/oleg/cont...', 646, Array)
#1 basic/vendor/yiisoft/yii2/rbac/PhpManager.php(91): yii\rbac\PhpManager->load()
#2 basic/vendor/yiisoft/yii2/base/Object.php(107): yii\rbac\PhpManager->init()
#3 [internal function]: yii\base\Object->__construct(Array)
#4 basic/vendor/yiisoft/yii2/di/Container.php(372): ReflectionClass->newInstanceArgs(Array)
#5 basic/vendor/yiisoft/yii2/di/Container.php(151): yii\di\Container->build('yii\\rbac\\PhpMan...', Array, Array)
#6 basic/vendor/yiisoft/yii2/BaseYii.php(344): yii\di\Container->get('yii\\rbac\\PhpMan...', Array, Array)
#7 basic/vendor/yiisoft/yii2/di/ServiceLocator.php(133): yii\BaseYii::createObject(Array)
#8 basic/vendor/yiisoft/yii2/di/ServiceLocator.php(71): yii\di\ServiceLocator->get('authManager')
Ответить

 

Роман

Имел ввиду, что изучаю Yii2. И не знал как организовать разграничение прав.

В любом случае Вы даёте полезный материал.
Спасибо.

Ответить

 

Антон – host-css.ru

Подскажите в чем может быть проблема

root@acer:/var/www/html/yii# php yii rbac/init
Exception 'Error' with message 'Call to a member function removeAll() on null'

in /commands/RbacController.php:20
Ответить

 

Антон Бурый

волшебный коммент :) Написал и понял что в config/console.php нужно прописать новые настройки AuthManager. Спасибо вам. Очень крутые статьи.

Ответить

 

евген – pro-club.org

у вас на гитхабе есть yii2-hybrid-authmanager. скажите, это усовершенствованный вариант описанного в этой статье Rbac?
можно узнать как он устроен? мультироли как хранятся? json в поле role?

Ответить

 

Дмитрий Елисеев

Посмотрите в следующей статье, на которую дана ссылка в конце этой.

Ответить

 

Maksimus1991

Спасибо, отличная статья)

Ответить

 

Юрий

Добрый день!!!

Спасибо за Ваши труды..
я столкнулся с такой проблемой, у нас есть модуль user в нем вид
views/backend/user/login.php

для чего он там? у меня не получается им воспользоваться, мы закрыли модуль админ от не прошеных гостей, а как сделать переброс на вид login.php но уже админ..

Спасибо

Ответить

 

Дмитрий Елисеев

Это для использования в advanced-приложении. Если хотите воспользоваться именно им в basic, то в методе beforeAction модуля admin налету замените адрес:

Yii::$app->uset->loginUrl = ['/admin/user/user/login'];
return parent::beforeAction($action);
Ответить

 

Юрий

Спасибо такой способ лучше чем мой я делал через denyCallback в access модуля админ....

но результат один и тот же, так как все идет через админ, а админ разрешен только админам:)
то происходит зацикливание...
мне кажется нужно в access rule какое то правило прописать. что бы оно разрешало только логин гостям...
пробовал так..

......
'rules' => [
    [
        'allow' => true,
        'actions' => ['index'],
        'controllers' => ['login'],
        'roles' => ['?'],
    ],
    [
        'allow' => true,
        'roles' => [AdminRbac::PERMISSION_ADMIN_PANEL],
    ],
],
....
Ответить

 

Дмитрий Елисеев
'access' => [
    'class' => AccessControl::className(),
    'except' => ['site/login', 'site/error'],
    'rules' => [
        'allow' => true,
        'roles' => [AdminRbac::PERMISSION_ADMIN_PANEL],
    ],
],
Ответить

 

Юрий

Спасибо, Дмитрий
вот то что сделал работает
может кому пригодится


'access' => [
    'class' => AccessControl::className(),
    'except' => ['user/user/index'], 
    'rules' => [
        [
        'allow' => true,
        'roles' => [AdminRbac::PERMISSION_ADMIN_PANEL],
        ],
    ],
],
Ответить

 

Анатолий Белов

Всё здорово! но манера подачи в тексте запутывает в конец.

Идешь последовательно, последовательно ложные примеры, которые в дальнейшем разбиваются о более совершенные. Тут нужен простой копипаст, потом устранять ошибки интерпритатора, текст бесполезен в данном случае, он ничего не раскрывает и не объясняет.

Ответить

 

Дмитрий Елисеев

Это статьи для программистов, а не для копипастеров. Увы.

Ответить

 

Анатолий Белов

Конечно, я ожидал такой вариант ответа. Для программиста, ценно здесь ваше упорство, с которым вы раскрываете фреймворк. Такое ощущение, что утро вы начинаете с xdebug, а потом чистите зубы.

Просто предлагаю, сосредотачивать статьи на конечном варианте.

Я хочу разобраться как это работает, меня не жмет копипастить, по этому, эта статья не для копипастеров и не для таких как я. Мне нужно увидеть как это работает. В итоге у меня в ide куча вкладок, с гитхаба вкладки, статья. И не понятно, как свести всё воедино.

В итоге я разобрался. Теперь пишу в чем у меня возникли сложности при усвоении материала. Принимать это во внимание или отсылать меня лесом, дело ваше. Вам все равно спасибо, за труды! Эти статьи хорошие примеры, к ним претензий нет. Суть моего коммента описана выше. Я поймал это исключение при чтении, практически всего цикла статей по yii2. Еще раз спасибо, подписан давно, жду следующих открытий.

Ответить

 

андрей

Анатолий Белов Согласен полностью, писать статьи уже давно разучились все, но в топы все лезут и лезут.. Жаль гугл и яндекс на столько конченые, что забили уже на проверку сайтов

Ответить

 

HiStO rIaN

Эти статьи для долбаебов вроде тебя, уебок очкастый. Удали свой дерьмосайт и не засоряй инет своим гавнокодом! Тебе уже кучу людей сказало, что ты даун, ты ноль в программировании!

Запомни дятел, для программистов не нужны статьи, они и так все знают. Создай закрытое сообщество, раздай всем своим ссылки и сидите там, а не засоряйте собой поисковики! Реально заебали!

Никто блять не может по человечески обьяснять, лишь бы херь всякую написать и выложить! Только путаете всех, кто начинает разбираться. Как будто сами небыли на нашем месте! Очистить бы вам мозг от всего этого, и дать ваши статьи. Заебетесь разбираться.

Ответить

 

Дмитрий Елисеев

В топах ещё и другие статьи есть кроме моих. Так что в путь! :)

Ответить

 

HiStO rIaN

В топах есть такой же мусор гавнокодера! Так что в путь с названием "нахуй из инета" вместе со своими статьми

Ответить

 

Дмитрий Елисеев

Ну раз кругом один мусор, то лыжи точно не едут. Регистрацию вы из-за меня за этот год не осилите. Печаль-беда.

Ответить

 

Дмитрий Елисеев

Мои статьи все про процесс, а не про вам так сразу нужный результат. Просто скопипастить у меня вам ничего не получится. А нужно объяснение каждой вещи в примерах - смотрите другие статьи, документацию, исходники, Development Cookbook.

Ответить

 

Oleg

Добрый день.
При выполнении php yii roles/assign
выдает ошибку

Exception 'Error' with message 'Call to undefined method app\models\User::findOne()' in commands/RolesController.php:59
Ответить

 

Дмитрий Елисеев

Переделайте User в ActiveRecord.

Ответить

 

Андрей

Дмитрий, приветствую!
Я столкнулся с такой проблемой - при добавлении пермишенов для новых контроллеров в метод init, я в самом начале делаю

$authManager = \Yii::$app->authManager;
$authManager->removeAll();

Затем все пермишены пересоздаются, новые добавляются, но в таблице auth_assignment удаляются все записи и соответственно уже созданные пользователи с ролями теряют все свои возможности.
Как быть в такой ситуации? Неужели каждый раз нужно будет добавлять новый метод для новых пермишенов?
Может быть можно как-то делать бэкап текущих назначенных прав на лету?

Заранее спасибо за ответ!

Ответить

 

Дмитрий Елисеев

Либо бэкапить и восстанавливать в init, либо добавлять роли через миграции.

Ответить

 

Андрей

Вдруг кому пригодится

private function backup()
{
    Console::output('Create backup auth_assignment table to auth_assignment_back');
    $connection = \Yii::$app->getDb();
    $connection->createCommand("DROP TABLE IF EXISTS `auth_assignment_back`")->query();
    $connection->createCommand("CREATE TABLE `auth_assignment_back` LIKE `auth_assignment`")->query();
    $connection->createCommand("INSERT INTO `auth_assignment_back` SELECT * FROM `auth_assignment`")->query();
}

private function restore()
{
    Console::output('Restore data from auth_assignment_back table to auth_assignment');
    $connection = \Yii::$app->getDb();
    $connection->createCommand("INSERT INTO `auth_assignment` SELECT * FROM `auth_assignment_back`")->query();
}
Ответить

 

HiStO rIaN

очередная дерьмостатья ничего не объясняющая... где все перепутано.... гавнокодер как всегда

Ответить

 

Дмитрий Елисеев

Вам это так не нравится, что уже кучу статей прочитали? Да вы мазохист :)

Ответить

 

Anton Fedonyuk

в статье куча бесполезного кода: вроде вызова array_filter() при выводе Nav::widget() или класса Rbac - и так есть псевдонимы "@", "?".

Ответить

 

Дмитрий Елисеев

> вроде вызова array_filter() при выводе Nav::widget()

Это полезный код, очищающий список от пустых пунктов.

> или класса Rbac - и так есть псевдонимы "@", "?"

Это класс для констант с именами разрешений. Псевдонимами разрешния не заменить.

Ответить

 

Anton Fedonyuk

добавлять в список пустые значения чтобы потом их отфильтровывать это такое себе решение.

Ответить

 

Дмитрий Елисеев

> добавлять в список пустые значения чтобы потом их отфильтровывать это такое себе решение.

Некоторые пункты отключаются тернарными операторами. ​Предлагаете переписать на простыню if-ов?

> откуда в RBAC им взяться?

Оттуда же, откуда именам ролей.

Ответить

 

Anton Fedonyuk

я видимо не правильно выражаюсь - попробуем по другому: в RBAC Вы раздаете разрешения с помощью ролей, роль включает в себя множество разрешений. У пользователя может и должно быть несколько ролей. поэтому для доступа в админку достаточно роли admin/@, но для того чтобы добавить или отредактировать свой контент нужна роль (content) manager, для изменения чужого контента нужна роль moderator.

Ответить

 

Дмитрий Елисеев

Суть как раз в переходе от проверки ролей на проверку разрешений.

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

<?php if ($user->can('admin') || $user->can('moderator')): ?>
    <a href="/admin/comments">Комментарии</a>
<?php endif; ?>

Но если вдруг захотим добавить ещё одну роль support службы поддержки или выдать доступ к комментариям менеджеру, то придётся каждый раз эти if-ы по всему коду менять.

Но вместо этого удобнее сделать всего одно разрешение manageComments для доступа к комментариям:

<?php if ($user->can('manageComments')): ?>
    <a href="/admin/comments">Комментарии</a>
<?php endif; ?>

И теперь можем создавать сколько угодно ролей, проставляя в конфигурации доступные им разрешения:

user
    manageOwnContent
    manageOwnComments

admin
    controlPanel
    manageContent
    manageComments
    manageUsers

manager
    controlPanel
    manageContent

moderator
    controlPanel
    manageComments

Теперь чтобы добавить новую роль просто создаём её в конфигурации:

support
    controlPanel
    manageComments

без необходимости менять if-ы.

Роли все плоские, друг от друга никак не наследуются. Иначе бы мы заблудились в деревьях наследования.

Можно даже дать администратору возможность создавать новые роли в админке и проставлять галочками разрешения для них.

> У пользователя может и должно быть несколько ролей

При такой системе разрешений пользователю обычно достаточно одной роли. Если же какому-то пользователю нужен индивидуальный подход, то можно сделать новую роль лично для него.

Ответить

 

Anton Fedonyuk

Поймите уже наконец, RBAC - это довольно простая система управления доступом, нужна сложнее? используйте другую модель.

Один субъект может иметь несколько ролей.
Одну роль могут иметь несколько субъектов.
Одна роль может иметь несколько разрешений.
Одно разрешение может принадлежать нескольким ролям.

Роли назначаются субъектам, вследствие чего субъекты получают те или иные разрешения через роли. RBAC требует именно такого назначения, а не прямого - назначение разрешений субъектам, иначе это приводит к сложно контролируемым отношениям между субъектами и разрешениями.

Ответить

 

Дмитрий Елисеев

Ну так эту модель RBAC мы как раз и используем. Субъекту назначаем роль. Роль имеет несколько разрешений. Именно так через роль разрешения и назначаем, а не напрямую субъекту.

Так что не так?

Ответить

 

Anton Fedonyuk

"admin" - роль, "adminPanel" - ресурс.

Ответить

 

Дмитрий Елисеев

"admin" - роль. "allowAdminPanel" - разрешение.

Ответить

 

Anton Fedonyuk

Исправил описку в предыдущем комменте: "adminPanel" - ресурс.

меня смущает подобный код:

$adminPanel = $auth->createPermission('adminPanel');
$adminPanel->description = 'Admin panel';
$auth->add($adminPanel);
 
$user = $auth->createRole('user');
$user->description = 'User';
$auth->add($user);
 
$admin = $auth->createRole('admin');
$admin->description = 'Admin';
$auth->add($admin);
 
$auth->addChild($admin, $user);
$auth->addChild($admin, $adminPanel);
Ответить

 

Anton Fedonyuk

для просмотра разделов админки достаточно роли admin, изменение своих записей - manager и изменение любых записей - moderator

Ответить

 

Дмитрий Елисеев

Контент-менеджеру и модератору тоже нужна админка, чтобы там править контент и модерировать комментарии.

Ответить

 

Anton Fedonyuk

RBAC не подразумевает явного наследования ролей как это сделано у Вас. Для доступа на чтение админки у пользователя должна быть роль admin, но при этом он может иметь и роли manager/moderator позволяющие ему не только просматривать контент, но и редактировать.

Ответить

 

Anton Fedonyuk

> Но вместо этого удобнее сделать всего одно разрешение manageComments для доступа к комментариям

все верно, это разрешение которое может быть у нескольких ролей, эту часть я никоим образом не оспариваю.

Ответить

 

Дмитрий Елисеев

А в Yii псевдоним "admin/@" так не работает.

Ответить

 

Anton Fedonyuk

Вы не знаете что слеш применяется в качестве разделителя? а & - это "и"))

Ответить

 

Дмитрий Елисеев

Ссылку на это можно?

Ответить

 

Anton Fedonyuk

Wikipedia подойдет?

(Our New Zealand / Western Australia trip — наше путешествие по Новой Зеландии / Западной Австралии)

Ответить

 

Дмитрий Елисеев

Какое отношение это имеет к фреймворку Yii?

А так да, если ваш код умеет работать с масками, то используйте "admin/users" для конкретных разрешений, а в админку пускайте по "admin/@". Тогда отдельного разрешения "admin/panel" не понадобится.

Ответить

 

Anton Fedonyuk

"@" - alias "admin", подразумевалось admin(@), часто вместо скобок ставится слеш - на дешевых печатных машинках не было кнопок со скобками.

Ответить

 

Павел

Дмитрий, здравствуйте!

Как ограничить доступ на уровне контроллера/метода понятно. Но как ограничить на уровне модуля, разделенного на frontend и backend? Причем в обеих частях сайта могут быть контроллеры с одинаковым именем.
Как ограничить на уровне родительского модуля admin?

Ответить

 

Дмитрий Елисеев

Как вариант, можно в конфигурации:

'modules' => [
    'blog' => [
        'class' => '...',
        'as access' => [
            'class' => AccessControl::class,
            'rules' => [...],
        ],
    ],
],

Yii сам в этом плане не очень продуман.

Ответить

 

Васька

после констант, стало все ясно... автор не понимает вообще ничего в этом....... костыли гавнокодеров

Ответить

 

Дмитрий Елисеев

Поясните.

Ответить

 

Denis

Удивительно читать подобное. Опытные программисты либо аргументами давят либо игнорируют.

Ответить

 

Павел

в файле modules/user/Module.php в методе behaviors прописал прописал правило доступа к контроллерам модуля, но перестали работать консольные контроллеры этого модуля.

Выдает ошибку

Exception 'yii\base\InvalidConfigException' with message 'Failed to instantiate component or class "user".'

Ставлю в правила только

[
   'allow' => true,
   'actions' => ['*'],
],

и тоже самое, но если удалить поведение, то все нормально.

В чем может быть дело? Или AccessControl не совместим с консольными контроллерами?

Ответить

 

Дмитрий Елисеев

Просто AсcessControl лезет в Yii::$app->user, которого в консоли нет. Yii сам в этом плане не очень продуман.

Как вариант, можно навешивать правила на модуль в конфигурации:

'modules' => [
    'blog' => [
        'class' => '...',
        'as access' => [
            'class' => AccessControl::class,
            'rules' => [...],
        ],
    ],
],

вместо навешивания в behaviors() модуля. Тогда не будет путаницы прав фронтенда, бекенда и консоли.

Ответить

 

Алекс

Скачал ваше расширение для гибридного RBAC на GitHub так вот в классе AuthManager есть свойство
public $modelClass = 'app\models\User'; И это свойство делает доступным ваше расширении только для basic шаблона. Приходится переписывать его под себя под advanced
Если есть желание поправьте

Ответить

 

Дмитрий Елисеев

Все такие настройки в Yii переопределяются в конфигурации:

'components' => [
    ...
    'authManager' => [
        'class' => 'elisdn\hybrid\AuthManager',
        'modelClass' => 'common\models\User',
    ],
    ...
],
Ответить

 

Алекс

Уже сам догадался))) спасибо

Ответить

 

Олег

Спасибо за статью!
Вот этот фрагмент поправьте, пожалуйста:

"для простоты наследуем admin от user" -> "для простоты наследуем user от admin"

Ответить

 

Anton Fedonyuk

Вы смешиваете/путаете RBAC и ACL. Зачем создавать псевдо роль adminPanel? Разве наличие у пользователя роли admin не гарантирует ему доступ в админку?

В тексте куча дублирования:

> Для нашего случая нужны всего две роли user и admin. Можно создать только их и проверять доступ по этим ролям. Но более гибкий и предпочтительный вариант – это использование так называемых «разрешений» вроде adminPanel и подобных и привязка их к ролям.

и прямо за этим повторяете тоже самое:

> Использование имён разрешений вроде adminPanel в модулях предпочтительнее имён ролей вроде user или admin, так как на каждом сайте можно будет делать разных админов и пользователей, в любой последовательности привязывая к ним ваши разрешения.

Ответить

 

Дмитрий Елисеев

> Вы смешиваете/путаете RBAC и ACL.

RBAC удобен для общего разграничения по ролям и разрешениям для всех элементов. ACL - для индивидуального контроля по правилам для конкретного элемента. В чём именно путаница?

> Зачем создавать псевдо роль adminPanel?

Ответил как раз в первом повторе, что "более гибкий и предпочтительный вариант – это использование так называемых «разрешений» вроде adminPanel и подобных и привязка их к ролям". Это мы и делаем.

> Разве наличие у пользователя роли admin не гарантирует ему доступ в админку?

На это ответил во втором повторе, что "на каждом сайте можно будет делать разных админов и пользователей, в любой последовательности привязывая к ним разрешения". Админу эта роль доступ сгарантирует, а контент-менеджеру или модератору - нет.

Ответить

 

Anton Fedonyuk
Комментарий удалён
Ответить

 

Дмитрий Елисеев

> RBAC - это довольно простая система прав. Вы же пытаетесь выдать Ваш микс RBAC + ACL за RBAC, но adminPanel - это не роль, а метка ресурса.

Моё adminPanel - это не роль или метка ресурса, а разрешение.

Ответить

 

Anton Fedonyuk
Комментарий удалён
Ответить

 

Дмитрий Елисеев

> нет в RBAC никаких доп.разрешений, только доступ по ролям.

Не знаю как у вас, а у нас в RBAC всё есть.

Ответить

Оставить комментарий

Войти | Завести аккаунт | Войти через


(никто не увидит)





Можно использовать теги <p> <ul> <li> <b> <i> <a> <pre>