unchanged
Title
Simple RBAC
If you need simple Role based access control without the long RBAC process then
this article is just for you. Lets jump to the point.
## The user model
On your user table make a column named 'roles'. Create the model accordingly. It
will be named "User" here.
When you add users you can assign them a role among 'admin', 'user', 'staff' etc
etc.
## The authentication
In the file "protected/components/UserIdentity.php" write something
like:
~~~
[php]
class UserIdentity extends CUserIdentity
{
private $id;
public function authenticate()
{
$record=User::model()->findByAttributes(array('email'=>$this->username));
if($record===null)
$this->errorCode=self::ERROR_USERNAME_INVALID;
else if($record->password!==md5($this->password))
$this->errorCode=self::ERROR_PASSWORD_INVALID;
else
{
$this->id=$record->id;
$this->setState('roles', $record->roles);
$this->errorCode=self::ERROR_NONE;
}
return !$this->errorCode;
}
public function getId(){
return $this->id;
}
}
~~~
The important line is `$this->setState('roles', $record->roles);`
It adds user roles to their session.
You can fetch the role of the current user with
`Yii::app()->user->getState('roles')` or simply
`Yii::app()->user->roles`.
## Checking permissions: structure
Modify or create the "WebUser.php" file under the
"protected/components" directory so that it overloads the
`checkAccess()` method.
~~~
[php]
<?php
class WebUser extends CWebUser
{
/**
* Overrides a Yii method that is used for roles in controllers (accessRules).
*
* @param string $operation Name of the operation required (here, a role).
* @param mixed $params (opt) Parameters for this operation, usually the object
to access.
* @return bool Permission granted?
*/
public function checkAccess($operation, $params=array())
{
if (empty($this->id)) {
// Not identified => no rights
return false;
}
$role = $this->getState("roles");
if ($role === 'admin') {
return true; // admin role has access to everything
}
// allow access if the operation request is the current user's role
return ($operation === $role);
}
}
~~~
You can define your own logic in this `checkAccess()` methods.
**Make sure this class is used by Yii.** The config file
"protected/config/main.php" must contain:
~~~
[php]
'components' => array(
// ...
'user' => array(
'class' => 'WebUser',
),
~~~
*Sidenote:*
[CWebUser::checkAccess()] usually connects to the authorization system loaded in
Yii.
Here we are replacing it with a simple system that just deals with roles instead
of the hierarchical system defined by the derivatives of [CAuthManager]. See the
official tutorial, [Role-Based Access
Control](http://www.yiiframework.com/doc/guide/1.1/en/topics.auth#role-based-access-control)
for details.
## Checking permissions: usage
* In your PHP code, use `Yii::app()->user->checkAccess('admin')` to check
if the current user has the 'admin' role.
The call `Yii::app()->user->checkAccess('staff')` will return true if
the user has the role "staff" or "admin".
* In your controller, you can filter with `accessRules()` using the
"roles" attribute of the rule.
See examples below.
### How to filter access to actions
The controller must contain:
~~~
[php]
public function filters()
{
return array(
'accessControl', // perform access control for CRUD operations
);
}
public function accessRules()
{
return array(
array('allow',
'action'=>array('admin'), 'actions'=>array('admin'),
'roles'=>array('staff', 'devel'),
),
array('deny', // deny all users
'users'=>array('*'),
),
);
}
~~~
Here the "admin" action of the controller has restricted access: only
those with roles "staff" or "devel" can access it.
As described in the API doc of
[CAccessRule](http://www.yiiframework.com/doc/api/1.1/CAccessRule#roles-detail),
the "roles" attribute will in fact call
`Yii::app()->user->checkAccess()`.
### How to display a different menu according to roles
You can also use just one menu for all users based upon different roles. for
example
~~~
[php]
<?php
$user = Yii::app()->user; // just a convenience to shorten expressions
$this->widget('zii.widgets.CMenu',array(
'items'=>array(
array('label'=>'Users', 'url'=>array('/manageUser/admin'),
'visible'=>$user->checkAccess('staff')),
array('label'=>'Your Ideas', 'url'=>array('/userarea/ideaList'),
'visible'=>$user->checkAccess('normal')),
array('label'=>'Login', 'url'=>array('/site/login'),
'visible'=>$user->isGuest),
array('label'=>'Logout ('.Yii::app()->user->name.')',
'url'=>array('/site/logout'), 'visible'=>!$user->isGuest)
),
));
?>
~~~
## Going further: access context
A very usual need is to allow a user to update its own data but not other's.
In this case, the user's role is meaningless without the context: the data that
will be modified.
This is why [CWebUser::checkAccess()] has an optional "$param"
parameter. Now suppose we want to check is a user has the right to update a Post
record. We can write:
~~~
[php]
if (Yii::app()->user->checkAccess('normal', $post)) {
~~~
Of course `WebUser::checkAccess()` must be extended to use this
"$params" parameter.
This will depend on your application's logic.
For instance, it could be as simple as granting access iff `$post->userId ==
$this->id`.