RBAC и описание ролей в файле

Обсуждение документации. Переводы Cookbook и авторские рецепты.
Bartholomew
Сообщения: 110
Зарегистрирован: 2010.02.05, 01:58
Откуда: Нижний Новгород
Контактная информация:

Re: RBAC и описание ролей в файле

Сообщение Bartholomew »

Читаю http://yiiframework.ru/doc/cookbook/ru/access.rbac.file.
Возникли вопросы и дополнения.

Дополнения:
1. В коде

Код: Выделить всё

class WebUser extends CWebUser {
...
private function getModel(){
        if($this->_model === null){
            $this->_model = User::model()->findByPk($this->id);
        }
        return $this->_model;
    } 
предлагаю условие заменить на

Код: Выделить всё

if (!$this->isGuest && $this->_model === null) 
поскольку, если пользователь не авторизован, в первом случае происходит (судя по логам) такой запрос к базе:

Код: Выделить всё

SELECT * FROM `users` `t` WHERE `t`.`id` IS NULL LIMIT 1
Соответственно, после изменения условия, запроса не происходит.

2. Меня напрягает, что ради свойства "роль" из базы вытаскиваются все поля, когда остальные данные вроде как не используются совсем. Даже если предположить, что они могут понадобиться в дальнейшем, то мы уже выбрали данные при аутентификации и положили их в states. Может быть уточнить запрос?

Вопрос такой:
На 3 странице топика коммент:
Мой рецепт исключительно про хранение ролей в файлах. Если требуется хранить роли в БД: http://yiiframework.ru/doc/guide/ru/topics.auth
Во-первых, не очень понимаю, в чем принципальная разница между подходом в кукбуке и в мануале. Во-вторых, почему "хранение ролей в файлах"? Разве мы не вытаскиваем её из базы в коде, что я привел выше?
Bartholomew
Сообщения: 110
Зарегистрирован: 2010.02.05, 01:58
Откуда: Нижний Новгород
Контактная информация:

Re: RBAC и описание ролей в файле

Сообщение Bartholomew »

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

Код: Выделить всё

Yii::app()->user->logout();
Yii::app()->user->login(...); 
Все нормально, только последующий за этими действиями вызов setFlash результата не приносит.
Если не сделать logout() или передать параметр false то старая сессия и кукисы остаются.
Как быть?
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: RBAC и описание ролей в файле

Сообщение samdark »

За замечания спасибо. Обновил рецепт.
Во-первых, не очень понимаю, в чем принципальная разница между подходом в кукбуке и в мануале. Во-вторых, почему "хранение ролей в файлах"? Разве мы не вытаскиваем её из базы в коде, что я привел выше?
При подходе в мануале вся иерархия ролей хранится в БД, при подходе в кукбуке — только поле role модели пользователя.

С проблемой setFlash и logout не сталкивался. Вопросы:
1. setFlash не работает после логина?
2. Если да, минимальный код, чтобы это воспроизвести очень поможет.
Bartholomew
Сообщения: 110
Зарегистрирован: 2010.02.05, 01:58
Откуда: Нижний Новгород
Контактная информация:

Re: RBAC и описание ролей в файле

Сообщение Bartholomew »

Контроллер:

Код: Выделить всё

class ProfileController extends CCController // где CCController extends CController
{
    ...
    
    public function actionProfile()
    {
        $this->render('profile');
    }

    public function actionUpdate()
    {
        if (!empty($_POST['Profile']))
        {
            //модель
            $user = new UpdForm('update');

            if ($user->validate())
                Yii::app()->user->setFlash(...); // изменения сохранениы
            else
                Yii::app()->user->setFlash(...); // ошибки
        }

        $this->redirect($this->createUrl('profile/profile'));
    }
    
    // тут еще один экшн actionChangepass для смены пароля
    ...
 
Модель:

Код: Выделить всё

class UpdForm extends UsersAR // где UsersAR extends CActiveRecord
{
    ...
    
    public function rules()
    {
        return array (
            ...
            array('password_confirm', 'checkUserPass', 'on' => 'update, changepass'),
        );
    }

    // проверяет, что пароль для подтверждения, который ввел юзер, совпадает с паролем из БД,
    // заодно проверяя, что в БД нет юзеров с таким же логином и почтой, 
    // как те, на которые пользователь меняет свои
    public function checkUserPass($attribute, $params)
    {
        if (!$this->hasErrors())
        {
            $record = $this->model()->findByPk(Yii::app()->user->id);
            
            // сравнение с записями из БД
            ...
            
            // запоминаются новые данные для сохранения
            $record->regmail = $this->regmail;
            $record->username = $this->username;

            $identity = new UserIdentity($record);
            if (!$identity->update(array('regmail', 'username')))
                $this->addError('username', Yii::t('upd', 'profileUpdateFailed'));
            else $identity->login();    
            ...
        }
    }
}
 
ЮзерИдентити:

Код: Выделить всё

class UserIdentity extends CUserIdentity
{
    private $_id = null;
    private $record = null;
    private $attributes = array('lastlogin', 'lastip');

    public function __construct($username, $password = false)
    {
        if (is_string($username))
            parent::__construct($username, $password);
        elseif (is_a($username, 'AuthForm'))
            $this->errorCode = self::ERROR_NONE;
        elseif (is_a($username, 'UpdForm'))
        {
            $this->errorCode = self::ERROR_NONE;
            $this->record = $username;
            parent::__construct($this->record->regmail, $this->record->password);
        }
    }

    // тут 2 функции для аутентификации юзера и активации аккаунта после регистрации
    ...

    public function update($attributes = array())
    {
        $attributes = array_merge($attributes, $this->attributes);

        $this->setRecordAttributes();
        $this->record->saveAttributes($attributes)

        // вот оно!
        // то есть, запускается validate() из контроллера, в ней запускается эта функция,
        // и из модели запускается login. А потом уже setFlash.
        Yii::app()->user->logout();
        $this->setNewStates();
        
        return true;
    }

    private function setNewStates ()
    {
        $this->setState('regmail', $this->record->regmail);
        $this->setState('regdate', $this->record->regdate);
        $this->setState('userpic', $this->record->userpic);

        $this->_id = $this->record->id;
        $this->username = $this->record->username;
    }

    private function setRecordAttributes ()
    {
        $this->record->lastip = Yii::app()->user->getIP(); // моя функция в переопределенном CWebUser
        $this->record->lastlogin = new CDbExpression('NOW()');
    }

    public function login ()
    {
        if ($this->errorCode == self::ERROR_NONE)
            Yii::app()->user->login($this, Yii::app()->user->allowAutoLogin ? Yii::app()->params['userSessionTime'] : 0);
    }

    public function getId() {
        return $this->_id;
    }
}
 
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: RBAC и описание ролей в файле

Сообщение samdark »

Эквивалентно?

Код: Выделить всё

<?php
class TestController extends CController {
    function actionTest(){
         echo Yii::app()->user->getFlash('test');

         Yii::app()->user->logout();
         
         $identity = new UserIdentity('sam', '123123');
         if(!$identity->authenticate()){
             echo 'wrooong!';
         }

         Yii::app()->user->setFlash('test', 'test string');
    }
}
 
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: RBAC и описание ролей в файле

Сообщение samdark »

Чуть отладки:

Код: Выделить всё

<?php
class TestController extends CController {
    function actionTest(){
         echo 'before get '.session_id();
         echo '<pre>'.print_r($_SESSION, true).'</pre>';

         echo Yii::app()->user->getFlash('test');
         echo 'after get, before logout '.session_id();
         echo '<pre>'.print_r($_SESSION, true).'</pre>';

         Yii::app()->user->logout();
         echo 'after logout '.session_id();
         echo '<pre>'.print_r($_SESSION, true).'</pre>';

         $identity = new UserIdentity('sam', '123123');
         if(!$identity->authenticate()){
             echo 'wrooong!';
         }
         echo 'after login '.session_id();
         echo '<pre>'.print_r($_SESSION, true).'</pre>';

         Yii::app()->user->setFlash('test', 'test string');
         echo 'after setflash '.session_id();
         echo '<pre>'.print_r($_SESSION, true).'</pre>';
    }
}
 
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: RBAC и описание ролей в файле

Сообщение samdark »

Получаем
before get
after get, before logout 76ee0d2880da407815b5a9264825141d
Array
(
)
after logout
Array
(
)
after login
Array
(
)
after setflash
Array
(
[0757bcf0245e536a6864d2a6050e4f7cYii.CWebUser.flash.test] => test string
[0757bcf0245e536a6864d2a6050e4f7cYii.CWebUser.flash.counters] => Array
(
[test] => 0
)

)
т.е. после logout сессия убита намертво и больше не стартует.
Bartholomew
Сообщения: 110
Зарегистрирован: 2010.02.05, 01:58
Откуда: Нижний Новгород
Контактная информация:

Re: RBAC и описание ролей в файле

Сообщение Bartholomew »

Угу, спасибо. Добавил session_start() после logout — заработало.
Интересно, это баг или фича? :)
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: RBAC и описание ролей в файле

Сообщение samdark »

Ekstazi
Сообщения: 1428
Зарегистрирован: 2009.08.20, 22:54
Откуда: Молдова, Бельцы
Контактная информация:

Re: RBAC и описание ролей в файле

Сообщение Ekstazi »

Это фича, на скока я помню в api к logout передаётся параметр, убивать ли сессию.
Bartholomew
Сообщения: 110
Зарегистрирован: 2010.02.05, 01:58
Откуда: Нижний Новгород
Контактная информация:

Re: RBAC и описание ролей в файле

Сообщение Bartholomew »

Баг не в том, что сессия убивается, а в том что не стартует после.
NetStranger
Сообщения: 107
Зарегистрирован: 2010.03.17, 12:54

Re: RBAC и описание ролей в файле

Сообщение NetStranger »

У меня по данному рецепту не находит Yii::app()->user->role

Пишет Unknown authorization item "".

Ищу причины, кажется где то в районе Class Webuser.php , только почему - не пойму...

а мождет и нет, логинится верно, но когда пишу

Код: Выделить всё

if(Yii::app()->user->checkAccess('administrator')){
    echo "hello, I'm administrator";
} 
выдает вот ту ошибку
Вот, что можно сделать с помощью Yii - Teutonick.ru
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: RBAC и описание ролей в файле

Сообщение samdark »

Покажите конфиг с ролями.
NetStranger
Сообщения: 107
Зарегистрирован: 2010.03.17, 12:54

Re: RBAC и описание ролей в файле

Сообщение NetStranger »

Идентичный тому, что на сайте.

Код: Выделить всё

<?php
return array(
    'guest' => array(
        'type' => CAuthItem::TYPE_ROLE,
        'description' => 'Guest',
        'bizRule' => null,
        'data' => null
    ),
    'user' => array(
        'type' => CAuthItem::TYPE_ROLE,
        'description' => 'User',
        'children' => array(
            'guest', // отнаследуемся от гостя
        ),
        'bizRule' => null,
        'data' => null
    ),
    'moderator' => array(
        'type' => CAuthItem::TYPE_ROLE,
        'description' => 'Moderator',
        'children' => array(
            'user',          // позволим модератору всё, что позволено пользователю
        ),
        'bizRule' => null,
        'data' => null
    ),
    'administrator' => array(
        'type' => CAuthItem::TYPE_ROLE,
        'description' => 'Administrator',
        'children' => array(
            'moderator',         // позволим админу всё, что позволено модератору
        ),
        'bizRule' => null,
        'data' => null
    ),
); 
Вот, что можно сделать с помощью Yii - Teutonick.ru
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: RBAC и описание ролей в файле

Сообщение samdark »

Unknown authorization item "" означает, что где-то выполняется проверка на роль с именем "". Это может быть либо checkAccess ручной, либо accessRules контроллера. Проверяйте. Сам рецепт повторён мной множество раз, ошибки не очень вероятны.
dou
Сообщения: 5
Зарегистрирован: 2010.08.15, 11:56

Re: RBAC и описание ролей в файле

Сообщение dou »

Код: Выделить всё

    'guest' => array(
        'type' => CAuthItem::TYPE_ROLE,
        'description' => 'Guest',
        'bizRule' => null,
        'data' => null
    ), 
Как из этой записи, при дальнейшем использовании, получить поле description? Например при выводе таблицы пользователей, хотелось бы видеть вместо названия роли ее описание.
Спасибо!
dou
Сообщения: 5
Зарегистрирован: 2010.08.15, 11:56

Re: RBAC и описание ролей в файле

Сообщение dou »

что, совсем никак? или слушком просто ? ))
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: RBAC и описание ролей в файле

Сообщение samdark »

А как выводится список пользователей?
dou
Сообщения: 5
Зарегистрирован: 2010.08.15, 11:56

Re: RBAC и описание ролей в файле

Сообщение dou »

Код: Выделить всё

<?php $this->widget('zii.widgets.grid.CGridView', array(
    'id'=>'user-grid',
    'dataProvider'=>$model->search(),
//    'filter'=>$model,
    'columns'=>array(
        //'id',
        'login',
        'fio',
        'balance',
        'tel_gor',
        'tel_sot',
                'role',    //поле в БД, в котором хранится имя роли определенное в файле auth.php
        array(
            'class'=>'CButtonColumn',
        ),
    ),
)); 
 
Вот в место role необходимо вывести description. Не могу понять, от куда его достать :?

Так же есть форма добавления нового пользователя:

Код: Выделить всё

<div class="form">

<?php $form=$this->beginWidget('CActiveForm', array(
    'id'=>'user-register-form',
    'enableAjaxValidation'=>false,
)); ?>

    <p class="note">Необходимые поля<span class="required">*</span></p> 

    <?php //echo $form->errorSummary($model); ?>

    <div class="row">
        <?php echo $form->labelEx($model,'login'); ?>
        <?php echo $form->textField($model,'login'); ?>
        <?php echo $form->error($model,'login'); ?>
    </div>

    <div class="row">
        <?php echo $form->labelEx($model,'password'); ?>
        <?php echo $form->textField($model,'password'); ?>
        <?php echo $form->error($model,'password'); ?>
    </div>
    
    <div class="row">
        <?php echo $form->labelEx($model,'password2'); ?>
        <?php echo $form->textField($model,'password2'); ?>
        <?php echo $form->error($model,'password2'); ?>
    </div>
    
    <div class="row">
        <?php echo $form->labelEx($model,'fio'); ?>
        <?php echo $form->textField($model,'fio'); ?>
        <?php echo $form->error($model,'fio'); ?>
    </div>

    <div class="row">
        <?php echo $form->labelEx($model,'tel_sot'); ?>
        <?php echo $form->textField($model,'tel_sot'); ?>
        <?php echo $form->error($model,'tel_sot'); ?>
    </div>

    <div class="row">
        <?php echo $form->labelEx($model,'role'); ?>

        <?php echo $form->dropDownList($model,'role',
                                               $role, //Здесь по идее должен быть массив ролей пользователей.
                                               array('options'=>array('3'=>array('selected'=>'selected')))
                                      ); ?>

        <?php echo $form->error($model,'role'); ?>
    </div>
    <div class="row buttons">
        <?php echo CHtml::submitButton('Зарегистрировать'); ?>
    </div>

<?php $this->endWidget(); ?>
Как сформировать из файла auth.php массив $role состоящий из полей description ролей?
При этом в таблицу User в поле role должно записываться имя роли, а не ее описание!
P.S. Я только начинаю вникать в Web и это мой первый фреймворк, прошу сильно не пинать :)
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: RBAC и описание ролей в файле

Сообщение samdark »

Если грид выводит данные из базы, проще будет записать туда и описание.
Ответить