RBAC implementation in Yii framework - yii

I am trying to apply simple hierarchial user structure(for ex: super-admin,admin,user) in my Yii web app. Can I do it by using Yii's default AccessControl or is it required to implement in Rbac.

You can do this by using Yii's default Access Control.
What I normally do when I do not use RBAC is create a field in the ACL User database that contains values eg. Admin, Super Admin etc and then once logged in I assign it to the Yii::app()-user session variable in componetnst/UserIdentity.php "Notice $this->setState('accessCode',$user->accessCode);"
class UserIdentity extends CUserIdentity
{
private $_id;
public function authenticate()
{
$username=strtolower($this->username);
$user=Users::model()->find('LOWER(userName)=?',array($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->u_id;
$this->username=$user->userName;
$this->setState('accessCode',$user->accessCode);
$this->setState('userName',$this->username);
$this->setState('id',$this->_id);
$this->setState('accessCode',$user->accessCode);
$this->errorCode=self::ERROR_NONE;
}
return $this->errorCode==self::ERROR_NONE;
}
public function getId(){
return $this->_id;
}
}
No in my controllers I have something like
public function accessRules()
{
return array(
array('allow',
'actions'=>array('admin'),
'expression'=>'Yii::app()->user->accessCode & 8',
),
array('allow',
'actions'=>array('create','update'),
'expression'=>'Yii::app()->user->accessCode & 1',
),
array('allow',
'actions'=>array('view'),
'expression'=>'Yii::app()->user->accessCode & 4',
),
array('allow',
'actions'=>array('delete'),
'expression'=>'Yii::app()->user->accessCode & 2',
),
array('deny', // deny all users
'users'=>array('*'),
),
);
}
Notice the expression works like a if statement
I hope this helps

Related

restrict view based on user's value in model using rules in controller- yii

Is there a way to restrict view based on user's input in model in the controller?
I want to hide/show their own page based on their own choice.
profile_hide_show with values of 'p'=>public, 'f'=>friends, and 'm'=>me
public function accessRules()
{
return array(
array('allow',
'actions'=>array('view'),
'users'=>array('?'), //?based on user's selection in model,
),
);
}
The Yii access control allows you to perform basic control before descending into the local methods of the controller.
You can enable access control by using the 'expression' attribute of an access control list. For example :
public function accessRules(){
$owner_id = $this->loadModel()->owner_id;
return array(
array('allow',
'actions'=>array('action1'),
'expression'=>"{$user->id}=={$owner_id}",
),
array('allow',
'actions'=>array('action2'),
'expression'=>'(Yii::app()->user->id == ($_GET[\'id\']))',
),
array('allow',
'actions'=>array('action3'),
'expression'=>'"Yii::app()->controller->isEnabledByUser()',
)
);
}
If you see the expression for action3, you will see you can call functions that will return a true/false value that will be evaluated by the expression attribute.
public function isEnabledByUser(){
$user_id = Yii::app()->user->id;
$user = User::model()->findByPk($user_id);
if ($user->show_my_page == 'Y')
return true;
else
return false;
}
References
How to view data only made by the user?
Do this check in the action or loadModel function. You cannot access a model in the accessRules.
public function loadModel($id) {
$type = modelname();
$class = CActiveRecord::model($type);
$model = $class->findByPk($id);
if($model === null)
throw new CHttpException(404, 'The requested page does not exist.');
if($model->profile_hide_show != 'p')
throw new CHttpException(404, 'You cannot view this profile.');
return $model;
}

User Access Level Error 403 Although Accessed by Admin

I wanted to make a user access level, but I have problem the admin (whose id_level = 1) still cannot access the specified page.
Here I have EWebUser.php
<?php
class EWebUser extends CWebUser{
protected $_model;
protected function loadUser()
{
if ( $this->_model === null ) {
$this->_model = User::model()->findByPk($this->id);
}
return $this->_model;
}
function getLevel()
{
$user=$this->loadUser();
if($user)
return $user->id_level;
return 100;
}
}
?>
Then here is the accessRules method in UserController.php
public function accessRules()
{
return array(
.......
array('allow', // allow admin user to perform 'admin' and 'delete' actions
'actions'=>array('index','admin','delete'),
//'users'=>array('admin'),
'expression'=>'$user->getLevel()<=1',
),
.......
);
}
I cannot access localhost/myappname/user.php, it throws error 403, although I logged in as Admin (id_level = 1).
I figured out $this->_model = User::model()->findByPk($this->id); , I made change $this->id_user because in my model the Primary key is id_user not id but it throws another error: Property "EWebUser.id_user" is not defined. Anyone can help me solve this problem? Thanks in advance..
[SOLVED] by myself, I changed $this->_id = $user->username; to $this->_id = $user->id_user; in UserIdentity.php, there's no wrong codes on $this->_model = User::model()->findByPk($this->id); because the actual problem is in the UserIdentity

CGridView Sorting with relational table sorts by relaton Id parameter

I have problem in CGrid while on sorting a relational data using relational model in `` page.
Briefly my scenario:
I have a user model: Entities=> id,username
And a profile Model: Entities=> id, firstname,lastname, user_id,etc..
I want to list profile model and username from user model in CGrid, so that sorting and searching perms well. In my case sorting username is done by user_id not by username. I want to search it by username,so i do the following,
My Controller Action:
$model = new Profile('search');
$model -> unsetAttributes();// clear any default values
if (isset($_GET['Profile']))
$model -> attributes = $_GET['Profile'];
$this -> render('MyPage', array('model' => $model ));
My Model Relation:
public function relations() {
// NOTE: you may need to adjust the relation name and the related
// class name the relations automatically generated below.
return array(
'user' => array(self::BELONGS_TO, 'user', 'user_id'),);
}
Model Rules:
array( 'xxx,yyy,user_name', 'safe', 'on'=>'search' ),
And model search function
if(!empty($this->user_id)){
$criteria->with='user';
$criteria->order = ::app()->request->getParam('sort');// 'username ASC'
}
$criteria -> compare('user.username', $this->user_id, true);
My
$this->widget('zii.widgets.grid.CGrid', array(
'id'=>'profile-grid',
'dataProvider'=>$model->search(),
'filter'=>$model,
array('name'=>'user_id',
'header'=>User::model()->getAttributeLabel('username'),
'value' =>'$data->getRelated(\'user\')->username',
'type'=>'raw',
'htmlOptions'=>array('style'=>'text-align: center'),),
---------------
During sorting,sorting works perfectly but sorting is done on the basis of user_id not by username. Anything that i am missing to do so. Please suggest.
Reference:Here (I also tried as by declaring a public variable as suggesting in the link but bot workingg.)
Edit: After Issue Fixed.
Thanks for this link too.
Well, the wiki page you found is really a good start...
Here is an alternative way for doing this :
In your Profile model :
// private username attribute, will be used on search
private $_username;
public function rules()
{
return array(
// .....
array('username', 'safe', 'on'=>'search'),
// .....
);
}
public function getUsername()
{
// return private attribute on search
if ($this->scenario=='search')
return $this->_username;
// else return username
if (isset($this->user_id)) && is_object($this->user))
return $this->user->username;
}
public function setUsername($value)
{
// set private attribute for search
$this->_username = $value;
}
public function search()
{
// .....
$criteria->with = 'user';
$criteria->compare('user.username', $this->username, true);
// .....
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
'sort'=>array(
'attributes'=>array(
'username'=>array('asc'=>'user.username', 'desc'=>'user.username DESC'),
'*',
),
),
));
}
And in your view you should simply try :
$this->widget('zii.widgets.grid.CGridView', array(
'id'=>'profile-grid',
'dataProvider'=>$model->search(),
'filter'=>$model,
'columns'=>array(
// .....
'username',
// .....
),
);

how to get or create role in yii

I am a newbie to yii. I have stuck my mind with yii-tutorials for creating roles in yii. but I am not getting how can I create role in yii. means I want to create two roles admin & staff and I want to give different priviliage to them.
I have created a role in user table, but I am not getting that how can I create a role and can assign priviliages to them, please help me guys
Thanks in advance
In your copenents/UserIdentity.php
class UserIdentity extends CUserIdentity{
private $_id;
public function authenticate()
{
$record=Members::model()->findByAttributes(array('username'=>trim($this->username)));
if($record===null)
$this->errorCode=self::ERROR_USERNAME_INVALID;
else if($record->password!==md5(trim($this->password)))
$this->errorCode=self::ERROR_PASSWORD_INVALID;
else
{
$this->_id=$record->id;
$this->setState('username', $record->username);
$this->setState('name', $record->name);
$this->setState('type', $record->role);
$this->errorCode=self::ERROR_NONE;
}
return !$this->errorCode;
}
public function getId()
{
return $this->_id;
}
public function setId($id)
{
$this->_id = $id;
}
}
You can create a new column name as "role". set the members type "admin" or "staff" to role column.
Be careful to that line.
$this->setState('type', $record->role);
Create a new helper file. /protected/helpers/RoleHelper.php
class RoleHelper {
public static function GetRole(){
if (Yii::app()->user->type == "admin"){
//set the actions which admin can access
$actionlist = "'index','view','create','update','admin','delete'";
}
elseif (Yii::app()->user->type = "staff"){
//set the actions which staff can access
$actionlist = "'index','view','create','update'";
}
else {
$actionlist = "'index','view'";
}
return $actionlist;
}
}
and in your controllers -> accessRules function
public function accessRules()
{
return array(
array('allow', // allow authenticated user to perform 'create' and 'update' actions
'actions'=>array(RoleHelper::GetRole()),
'users'=>array('#'),
),
array('deny', // deny all users
'users'=>array('*'),
),
);
}
and dont forget to add 'application.helpers.*' to /config/main.php
'import'=>array(
'application.models.*',
'application.components.*',
'application.helpers.*',
),
This source is pretty good specially for beginners..I am using this method till now:
Simple RBAC in YII
Just follow the instructions given while having your desired modifications.
Concrete Example:
WebUser.php (/components/WebUser.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("evalRoles");
if ($role === 'SuperAdmin') {
return 'SuperAdmin'; // admin role has access to everything
}
if ($role === 'Administrator') {
return 'Administrator'; // admin role has access to everything
}
if ($role === 'Professor') {
return 'Professor'; //Regular Teaching Professor, has limited access
}
// allow access if the operation request is the current user's role
return ($operation === $role);
}
}
Just connect it with your components/UserIdentity.php and config/main.php:
'components' => array(
// ...
'user' => array(
'class' => 'WebUser',
),
and thats it..
to check the role of the logged in:
Yii::app->checkAccess("roles");
where checkAccess is the name of your function in WebUser...
Please note that evalRoles is a column in your table that will supply the role of an account (on my link provided, that would be the word roles used in the major part snippet)

how to use one model for two different forms?

I am currently working in yii, I have designed a user module which consists user registraion, user login & change password rule.
for these three process I have designed only one model i.e. user model. in this model I have defined a rule:
array('email, password, bus_name, bus_type', 'required'),
This rule is valid for actionRegister. but now I want to define a new required rule for actionChangePassword,
array('password, conf_password', 'required'),
How can I define rule for this action ?
Rules can be associated with scenarios. A certain rule will only be used if the model's current scenario property says it should.
Sample model code:
class User extends CActiveRecord {
const SCENARIO_CHANGE_PASSWORD = 'change-password';
public function rules() {
return array(
array('password, conf_password', 'required', 'on' => self::SCENARIO_CHANGE_PASSWORD),
);
}
}
Sample controller code:
public function actionChangePassword() {
$model = $this->loadModel(); // load the current user model somehow
$model->scenario = User::SCENARIO_CHANGE_PASSWORD; // set matching scenario
if(Yii::app()->request->isPostRequest && isset($_POST['User'])) {
$model->attributes = $_POST['User'];
if($model->save()) {
// success message, redirect and terminate request
}
// otherwise, fallthrough to displaying the form with errors intact
}
$this->render('change-password', array(
'model' => $model,
));
}