Use Rbac To Check Access In Controller

Ok I’ve setup my Yii base website created using yiic, and add in yii-user and rights module.

And I follow below guide

www.benjaminlhaas.com/blog/installing-yii-users-and-rights-5-steps

Scenario: I created a module called Requests. There are 2 users under Admin and Guest. I want to only allow Guest to access the ‘index’ page of Requests, but not ‘create’ page




authassignment

itemname 	userid 	bizrule 	data

Admin 		1 	NULL		N;

Guest 		2 	NULL		N;






authitem

name 		type 	description 	bizrule 	data

Admin 		2 	NULL 		NULL 		N;

Guest 		2 	NULL 		NULL 		N;

Requests.* 	1 	NULL 		NULL 		N;

Requests.Index 	0 	NULL 		NULL 		N;






authitem

name 		type 	description 	bizrule 	data

Admin 		2 	NULL 		NULL 		N;

Guest 		2 	NULL 		NULL 		N;

Requests.* 	1 	NULL 		NULL 		N;

Requests.Index 	0 	NULL 		NULL 		N;

Requests.Create	0 	NULL 		NULL 		N;






authitemchild

parent 	child

Guest 	Requests.Index



Now as you see above I’m trying to restrict Guest role to only go to index, not to create. So I code as below in RequestsController:


public function actionIndex() {

   if (!Yii::app()->user->checkAccess('index'))

      Yii::app()->end();

   // ... more code

}


public function actionCreate() {

   if (!Yii::app()->user->checkAccess('create'))

      Yii::app()->end();

   // ... more code

}

Is above the correct way to utilize RBAC to check access in Controller? I’m not sure whether I’m doing it correctly, thus out of idea how actually to implement RBAC?

first of all - more elegant way is to utilise authentication filters to check access to specific actions:




public function filters() {

  return array(

    'accessControl', // perform access control for CRUD operations

  );

}


public function accessRules() {

  return array(

    array( 'allow',

      'actions'=>array( 'index' ),

      'roles'=>array( 'Requests.Index', 'Requests.*' ),

    ),

    array( 'allow',

      'actions'=>array( 'create' ),

      'roles'=>array( 'Requests.Create', 'Requests.*' ),

    ),

    array( 'deny' ),

  );

}


public function actionIndex() {

   // ... more code

}


public function actionCreate() {

   // ... more code

}



as you can see filter assures that action can be called only by users having specific roles. First matching rule wins, so if none match - there is default last one which rejects everything else.

Second thing is role/operation naming. You must use exactly same name as authitem, so you cannot just do:


Yii::app()->user->checkAccess('index')

but rather


Yii::app()->user->checkAccess('Requests.index')

because you created such auth item.

Thanks redguy! I managed to get it working! And instead of putting checkAccess in every Controller’s methods, I will follow your recommendation to put in accessRules.

Now I’ve something like this (note the ‘users’):




public function accessRules()

{

	return array(

                //a.

		array('allow',  // allow all users to perform 'index' and 'view' actions

			'actions'=>array('index','view'),

			'users'=>array('*'),

			'roles'=>array( 'Requests.Index', 'Requests.*' ),

		),

                //b.

		array('allow', // allow authenticated user to perform 'create' and 'update' actions

			'actions'=>array('create','update'),

			'users'=>array('@'),

			'roles'=>array( 'Requests.Create', 'Requests.*' ),

		),

	);

}



My layman interpretation

a. Allow index and view page access for all users with roles ‘Requests.Index’, ‘Requests.*’

b. Allow create and update page access for logged-in users with roles ‘Requests.Create’, ‘Requests.*’

Questions:

  1. Are my interpretation above correct?

  2. is it logical ‘users’ and ‘roles’ exist together?

  3. Why we need to put Requests., does it mean all? (users with ‘Requests.Index’, 'Requests.’ isn’t it seems redundant?)

  1. generally you are right, but I do not see any reason to use both ‘users’ and ‘roles’. I would go only with ‘roles’ - if someone has role assigned - he is allowed to do something.

  2. same as above

  3. that was my mistake. If "Requests.*" auth item aggregates all "Requests.XXX" items then all you need in accessRules is just "Requests.Index".