Integrating RBAC using Yii CphpAuthManager
Earlier, I had written a post on the topic “Integrating RBAC using CdbAuth Manager” and while concluding it, I had promised to hit back soon with another integration method on the same, well, here I ‘am. With this post, I would like to try to explain the integration of RBAC using Yii CphpAuthManager. As the title indicates, this post will depict the integration of the Role Based Acess Control or RBAC using a PHP file, rather than using a database. The PHP file used here is supposedly controlled by the CphpAuth Manager class.
Role configuration
When you are setting up an RBAC, the Yii will automatically scan for defined roles, for the cause, it usually scans any file with the name auth.php that is normally located in the path protected/data/auth.ph. Therefore, it is necessary for you to create this file and assign the roles as intended. Bear in mind that while reading an auth.php file, the Yii expects to encounter an array, so see that you return an array () using this file. It is also necessary to cater Yii with enough permission to write into this file so that it can do the necessary corrections when changing roles.
Yii could make changes to the auth.php file turning it to be pretty hard to edit. Therefore, the right idea is to edit use an auth.txt file and copy its content to the auth.php file whenever necessary. Configure the roles in the auth.txt file as follows:
// protected/data/auth.php
return array(
‘reader’ => array (
‘type’=>CAuthItem::TYPE_ROLE,
‘description’=>’Can only read a post’,
‘bizRule’=>”,
‘data’=>”
),
‘commentor’ => array (
‘type’=>CAuthItem::TYPE_ROLE,
‘description’=>’Can post a comment’,
‘bizRule’=>”,
‘data’=>”
),
‘admin’ => array (
‘type’=>CAuthItem::TYPE_ROLE,
‘description’=>’Can read a post and post a comment’,
‘children’=>array(
‘reader’,’commentor’
),
‘bizRule’=>”,
‘data’=>”
)
);
You can see three types of declarations highlighted in the above code:
- Admin: who has provisions to read and comment to posts
- Commentor: who only has access to posts for which comment is enabled.
- Reader: who can read any posts but has no right to comment.
cphpAuthManager requires bizRules and data here.
Once the file is edited, place it in the desired location:
$ cp auth.txt auth.php
$ chmod a+w auth.php _# make sure Apache can write to it_
Whenever you need to make some changes to the roles, see that you make it in the auth.txt file and copy it into the auth.php file.
acessRules Configuration
We have already set up the roles and the next step is to apply them in action. The below code depicts the application of codes to PostController:
// in protected/controllers/PostController.php
class PostController extends CController {
public function filters()
{
return array(
‘accessControl’ // required to enable accessRules
);
}
public function accessRules()
{
return array(
array(‘allow’, // allow readers only access to the view file
‘actions’=>array(‘view’),
‘roles’=>array(‘reader’)
),
array(‘deny’, // deny everybody else
‘users’ => array(‘*’)
)
);
}
…
tbl_user configuration:
As the next step, we need to add a tbl_user field in the database. The new field is supposed to come with some user entries.
After the tbl_user table is set up, it is our duty to inform Yii whether a sign-in is actually a reader, a commentor or an admin. This step is depicted below using a User identity class:
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:
$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
}
}
Configuring main.php file to use AuthManager
$auth=Yii::app()->authManager;
The code snippet above is used to initialize the authManager and this is to be setup in the protected/config/main.php config file as follows:
// protected/config/main.php
return array(
…
‘components’=>array(
‘authManager’=>array(
‘class’=>’CPhpAuthManager’,
// ‘authFile’ => ‘path’ // only if necessary
),
…
This code ideally informs the Yii that we would like the CphpAuthManager to handle our accessControl. It is necessary to test our functionality and to get this done, we need to add RBAC checks to views/post/view.php:
<?php if(Yii::app()->user->checkAccess(‘commentor’)): ?>
<h3>Leave a Comment</h3>
………//your /comment/_form here
<?php endif; ?>
The above code is used to check whether the user has the provision to post comments and it is placed around the comments from section in the view file.
Now, as the last step, it is necessary for you to delete role assigned to a user once he/she logs out, else if he logs in again, he will be assigned with two roles. Use the below written code to get this task done.
// protected/controllers/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
}
Hope this post was encouraging enough for you to try this integration. Any doubts on this? Feel free to drop in a comment and I will get back to you soon enough.