Difference between #3 and #2 of How to setup RBAC with a php file

unchanged
Title
How to setup RBAC with a php file
unchanged
Category
Tutorials
unchanged
Tags
changed
Content
In this cookbook I will attempt to explain how to use the lightweight version of
[Role-Based Access
Control](http://www.yiiframework.com/doc/guide/topics.auth#role-based-access-control)
using a php file. This version does not use database but a php file and is
controlled by CPhpAuthManager class.

## Configuring the roles: ##

By default when setting up this particular type of rbac Yii will look for any
defined roles in a file named auth.php and located in protected/data/auth.php
For the sake of easiness I will  add an example of user rbac to the blog demo. 

>Info: Yii expects to read auth.php and get an array() out of it. So we need
to create auth.php and return array(); Yii also needs to write to that file when
changing roles so make sure to provide enough permission access to that file
needed by the system.

Next we declare some roles in our auth.php file:
~~~
[php]

return array(
'reader' => 
  array (
     'type'=>CAuthItem::TYPE_ROLE,
     'description'=>'Can only read a post',
   ),

'commentor' => 
  array (
     'type'=>CAuthItem::TYPE_ROLE,
     'description'=>'Can post a comment',
   ),

'admin' => 
  array (
     'type'=>CAuthItem::TYPE_ROLE,
     'description'=>'Can read a post and post a comment',
         'children'=>array(
           'reader','commentor',
         },
   ),
),
~~~

The above code declares 3 different types of roles:

1 - reader - this type of role can only read a post but not post any comments

2 - commentor - this role gives access only to the comments form section to post
a comment.

3 - admin - which can read a post and post a comment (consists of both roles
above).

## Configuring the accessRules(): ##

Now that we've setup our roles we should move to apply them in action. In this
example I will only apply them to our PostController as below:

~~~
[php]
public function accessRules()
            {
                return array(
                    array('allow', // allow readers only access to the view file
                        'actions'=>array('view'),
                        'roles'=>array('reader'),
                    ),
                );
            }
~~~

The above code should be pretty clear - allow user with 'reader' role access to
the view action.

## Configuring our tbl_user in our database: ##

Next we add an additional field to our tbl_user. We call that field role
(varchar 30). We also need two user entries in this table. We already have the
'demo' one from the blog tutorial and add a 'test' one. In the 'demo' role field
entery 'reader' as data and for 'test' enter 'admin' as a role.

## Assigning roles: ##

Now we need to tell Yii when a user logs in what role s/he gets. I do this part
in my UserIdentity class which takes care of my authentication for my blog. Here
is how my UserIdentity class looks like:

~~~
[php]
public function authenticate()
	{
		$user=User::model()->find('LOWER(username)=?',array(strtolower($this->username)));
		if($user===null)
			$this->errorCode=self::ERROR_USERNAME_INVALID;
		else if(!$user->validatePassword($this->password))
                        {
			$this->errorCode=self::ERROR_PASSWORD_INVALID;
                        }
		else
		{
			
                        $this->_id=$user->id;
			$this->username=$user->username;
                        $auth=Yii::app()->authManager;
                        if(!$auth->isAssigned($user->role,$this->_id))
                            {
                            if($auth->assign($user->role,$this->_id))
                                    {
                                Yii::app()->authManager->save();
                            }
                            
                        }
                        
			$this->errorCode=self::ERROR_NONE;
		}
		return $this->errorCode==self::ERROR_NONE;
	}
~~~

The code we have added to the original UserIdentity class is:

~~~
[php]
                        $auth=Yii::app()->authManager; //initializes the
authManager
                        if(!$auth->isAssigned($user->role,$this->_id))
//checks if the role for this user has already been assigned and if it is NOT
than it returns true and continues with assigning it below
                            {
                            if($auth->assign($user->role,$this->_id))
//assigns the role to the user
                                    {
                                Yii::app()->authManager->save(); //saves
the above declaration
                            }
                            
                        }
~~~
>Info: Please see comments at the end of the lines for explanation on what
every line of code does. It is important to remember that it is good practice to
check if a roles has already been assigned becuase Yii assignes roles and does
not delete them until you call the revoke() function. In canse you forget and
try to re-assign a role Yii will return an error. Another important point is
when you assign a role you must save it by calling
Yii::app()->authManager->save();


## Configuring our main.php to use authManager: ##

~~~
[php]
$auth=Yii::app()->authManager;
~~~
The code snippet above initializes the authManager, which we need to setup in
our protected/config/main.php config file as follows:
~~~
[php]
'components'=>array(
    'authManager'=>array(
                     'class'=>'CPhpAuthManager',
                ),
),
~~~
This basically activates the authorization Manager of the application and tells
yii that we want to use CPhpAuthManager class to take care of our
accessControll. When you login Yii will assign a role to your user id. After you
login open up the auth.php file and see that Yii has re-aranged it in the
appropriate way.

For the sake of testing our functionality we should now add some rbac check to
our views/post/view.php:
~~~
[php]
<?php if(Yii::app()->user->checkAccess('commentor')): ?>

	<h3>Leave a Comment</h3>
            .........//your /commnet/_form here
<?php endif; ?>
~~~

Place the above code around your comments form section in the view file to check
if the user has enough access privileges to post a comment.

You should now have a working privilege based system. One more thing left for
our cookbook to be complete. 

>Info: When the user logs out we need to delete the assigned role otherwise
if you change that user's role while he is offline and when he comes back and
logs in again he will end up with two roles: the old one and the new one! So we
place the below code in our logout action in the SiteController:


~~~
[php]
public function actionLogout()
	{
                $assigned_roles =
Yii::app()->authManager->getRoles(Yii::app()->user->id); //obtains
all assigned roles for this user id
                if(!empty($assigned_roles)) //checks that there are assigned
roles
                    {
                    $auth=Yii::app()->authManager; //initializes the
authManager
                    foreach($assigned_roles as $n=>$role)
                        {
                        if($auth->revoke($n,Yii::app()->user->id))
//remove each assigned role for this user
                        Yii::app()->authManager->save(); //again always
save the result
                    }
                    
                }
                Yii::app()->user->logout(); //logout the user
		$this->redirect(Yii::app()->homeUrl); //redirect the user
	}
~~~

## Adiitional/optional settings: ##

In your auth.php file you can use the following parameters:
- __`type`__ => role,task,operation
- __`description`__ => describe the type
- __`bizRule`__ => apply business rule
- __`data`__ => used in the business rule
- __`children`__ => inherit other roles/tasks/operations

The 'type' is represented by the following constants in the CAuthItem class:
~~~
[PHP]
const TYPE_OPERATION=0;
const TYPE_TASK=1;
const TYPE_ROLE=2;
~~~

## Related readings
[Role-Based Access
Control](http://www.yiiframework.com/doc/guide/topics.auth#role-based-access-control)<br
/>
[CModel::rules()](/doc/api/CModel#rules-detail)<br />
[CAuthManager](http://www.yiiframework.com/doc/api/CAuthManager)<br />
[RBAC
clarification](http://www.yiiframework.com/forum/index.php?/topic/2313-rbac-confusion)<br
/>
[another related rbac
approach](http://yiiframework.ru/doc/cookbook/ru/access.rbac.file)<br
/>

>Disclaimer: The above code works for me. I do not guarantee that it will
work in all situations. If you need more complex rbac structure use the DB one.
I've read all posts in the forum RE rbac but none of them helped me so the above
code has been discovered through trial & error. Use it on your own
responsibility.