You are viewing revision #2 of this wiki article.
This version may not be up to date with the latest version.
You may want to view the differences to the latest version or see the changes made in this revision.
If you are the one who need simple Role based access control without the long RBAC process then this article is just for you. Lets jump to the point.
On your user table make a column named 'roles'
When you add users you can assign them different roles like 'Admin' / 'user' / 'staff' etc etc.
On your UserIdentity.php file write something like..
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);
You are just adding user roles to their session.
Now, make a Utils.php file under protected/components directory and implement a simple Role check function based on how many roles you have.
<?php
class Utils{
public function isAdmin(){
if(Yii::app()->user->isGuest)
return false;
else if(Yii::app()->user->roles == 'Admin')
return true;
else
return false;
}
public function isUser(){
if(Yii::app()->user->isGuest)
return false;
else if(Yii::app()->user->roles == 'User')
return true;
else
return false;
}
}
?>
And now, from your controller accessRules() function try something like
public function accessRules()
{
return array(
array('allow',
'controllers'=>array('admin'),
'expression'=>'Utils::isAdmin()',
),
array('deny', // deny all users
'users'=>array('*'),
),
);
}
Here I just protect my AdminController.php from other roles than Admin. Basically from AdminController.php file accessRules() function it checks the users Roles written in Utils.php file.
You can also use just one menu for all users based upon different roles. for example
<?php $this->widget('zii.widgets.CMenu',array(
'items'=>array(
array('label'=>'Users', 'url'=>array('/manageUser/admin'), 'visible'=>Utils::isAdmin()),
array('label'=>'Ideas', 'url'=>array('/manageIdea/admin'), 'visible'=>Utils::isAdmin()),
array('label'=>'Page Editor', 'url'=>array('/admin/pageeditor'), 'visible'=>Utils::isAdmin()),
array('label'=>'Your Ideas', 'url'=>array('/userarea/ideaList'), 'visible'=>Utils::isUser()),
array('label'=>'Add new idea', 'url'=>array('/userarea/create'), 'visible'=>Utils::isUser()),
array('label'=>'Login', 'url'=>array('/site/login'), 'visible'=>Yii::app()->user->isGuest),
array('label'=>'Logout ('.Yii::app()->user->name.')', 'url'=>array('/site/logout'), 'visible'=>!Yii::app()->user->isGuest)
),
)); ?>
I hope this little code will help you
Thanks
The method isAdmin, isUser are not static
I have one doubt, since the methods isAdmin, isUser etc of Utils class are not static (public Methods) How can we refer them as Utils::isAdmin in access rules or i Zii widgest?
Great text!
Hi, Thank you for a great text! I've been looking for "as simpliest as possible" solution like that, to incorporate it into smaller projects, that do not need a complex, "heavy" RBAC module. Thank you again.
Importantly
If set autoLogin=>true in config all data will saved in cookie and i can change my role. WebUser it's better place for method getRole().
Thanks
Thank you very much for the text.
very useful
I had the idea, thanks.
Multiple Role Check
Update: Please see Derek++ comment http://www.yiiframework.com/wiki/328/simple-rbac/#c18942 My usage of strtstr() is incorrect.
Hello,
I needed to be able to check for multiple roles. With a minor change I can now do this:
Yii::app()->user->checkAccess('user,manager,admin')
*Note: you can do any combination | ; , .
I just choose commas. The command will find any match.
Place the following below $role === 'admin' in protected/components/WebUser.php
if (strstr($operation,$role) !== false) { // Check if multiple roles are available return true; }
Full protected/components/WebUser.php file:
<?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"); // Get role of user if ($role === 'admin') { return true; // admin role has access to everything } if (strstr($operation,$role) !== false) { // Check if multiple roles are available return true; } return ($operation === $role);// allow access if the operation request is the current user's role } }
How to display a different menu according to roles:
You can also use YiiSmartMenu extension.
$this->widget('ext.YiiSmartMenu',array( //calls YiiSmartMenu 'items'=>array( array('label'=>'Users', 'url'=>array('/manageUser/admin'), 'authItemName'=>'staff', //define what should be checked ...
checkAccess
Sorry guys, but this point it's not really clear for me
"The call Yii::app()->user->checkAccess('staff') will return true if the user has the role "staff" or "admin"."
What do i've to specify inside checkAccess?
In my app, I've 3 user types (admin, operator, account) and i'd like to filter the access inside controllers and filter displayed content.
Inside the controller, i use
public function accessRules() { return array( array('allow', 'roles'=>array(User::ROLE_ADMIN,User::ROLE_OPERATOR), ), array('deny', // deny all users 'users'=>array('*'), ), ); }
where User::ROLE_ADMIN and User::ROLE_OPERATOR are int 1 and 2, and it's the value assigned inside userIdentity
$this->setState('roles', $record->role_id);
where $record->role_id can be 1 or 2
But it's not working, if i chanche the accessRules with
'roles'=>array(User::ROLE_ADMIN),
users with User::ROLE_OPERATOR can access anyway. :(
Any suggestion? Thank you
ps:
this is the code inside checkAccess
$role_id = $this->getState('roles'); if(($role_id == User::ROLE_ADMIN) || ($role_id == User::ROLE_OPERATOR)) return true; else throw new CHttpException(404, '');
One user with multiple roles
If you want to assign multiple roles to a user (separated by a comma) you can replace
$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);
with
$roles = explode(',', $this->getState("roles")); if (in_array('admin', $roles) || in_array($operation, $roles)) return true;
How to create Access (view page) role in yii ?
Hi guys
How to create access role in yii and where in yii application part ?
I want to create access role in yii application but i have a problem and dont know about where to assign role in yii like
i have three department role
1.admin -: admin have a all access role in our application
2.staff -: staff same of page and access role like to edit or update
3.user -: user have a all access page only viewing in our application
These type of role can set in controller but i can justify where to write all access in yii and how to set access role ,
thank
hari maliya
I con't access action according to role ?
Hi guys
I try to all type of set access role and set role ,
I got role in controller but this can't be access a action page
thnaks
hari maliya
Great and simple
Work great for small projects, thanks for the wiki!
Property User.roles is not defined
Hi, I just a newbie in Yii. I have read this article and followed all instructions here, but I had error User.roles is not defined when I tried to login.
Here is my UserIdentity.php
<?php class UserIdentity extends CUserIdentity { private $_id; public function authenticate() { $user = User::model()->findByAttributes(array ('username'=>$this->username)); if($user===null){ $this->errorCode=self::ERROR_USERNAME_INVALID; } else{ if($user->password!==$user->encrypt($this->password)){ $this->errorCode=self::ERROR_PASSWORD_INVALID; } else{ $this->_id = $user->username; $this->setState('roles', $user->roles); $this->errorCode=self::ERROR_NONE; } } return !$this->errorCode; } public function getId(){ return $this->_id; } }
And then EWebUser.php
<?php class EWebUser extends CWebUser { 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); } }
At last accessRules method in UserController.php
public function accessRules() { ..... return array( array('allow', // allow admin user to perform 'admin' and 'delete' actions 'actions'=>array('admin','delete'), //'users'=>array('admin'), 'roles'=>array('admin'), ..... ); }
I hope anyone can help solve this problem, thank you very much.
Arnold Gultom
Hi,
On your User model did you create a column called role or roles. In the example they have created a column called roles, which is not clear.
The key is this line:
$this->setState('roles', $record->roles);
It says assign the column "roles" from the record to a state variable called "roles".
Hope this helps.
Neil
Regarding Roles Column
Hi,
On your user table make a column named 'roles'.
Details described here.
http://www.yiiframework.com/wiki/328/simple-rbac/#hh0
Thank you very much.
Thank you very much for this document.Very useful for me.
Thank!
Re: Multiple Role Check
You shouldn't use strstr() for the role check. If there are two roles named user and superuser then a check for user will always match superuser as well. Better to use array search or have an explicit delimiter...
// would need to change input to an array // E.g. Yii::app()->user->checkAccess(array('user','superuser')) if(is_array($operation)) { return (array_search($role,$operation)!==false); } // ...or use an explicit delimiter and explode the string if(strpos($operation, ',')) { $operation_arr = explode(',',$operation); return (array_search($role,$operation)!==false); } // ...or use an explicit delimiter with padding if (strstr(','.$operation.',' , ','.$role.',') !== false) { return true; }
Here is the updated version...
<?php class WebUser extends CWebUser { /** * Overrides a Yii method that is used for roles in controllers (accessRules). * * @param mixed $operation Name of the operation required (here, a role). Can be either string or an array of roles. * @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"); // Get role of user if ($role === 'admin') { return true; // admin role has access to everything } if(is_array($operation)) { // Check if multiple roles are available return (array_search($role,$operation)!==false); } return ($operation === $role);// allow access if the operation request is the current user's role } }
If you have any questions, please ask in the forum instead.
Signup or Login in order to comment.