I'm trying to build a site using Yii, and found myself in a situation which requires some clarifications on access control metaphor in Yii. Specifically, one can override accessRules method in CController
's descendant.
Prerequisite:
Here is a code generated by default by Gii, much similar to the documentation:
public function accessRules()
{
return array(
array('allow', // allow all users to perform 'index' and 'view' actions
'actions'=>array('index','view'),
'users'=>array('*'),
),
array('allow', // allow authenticated user to perform 'create' and 'update' actions
'actions'=>array('create','update'),
'users'=>array('@'),
),
array('allow', // allow admin user to perform 'admin' and 'delete' actions
'actions'=>array('admin','delete'),
'roles'=> array('admin'),
),
array('deny', // deny all users
'users'=>array('*'),
),
);
}
The Question:
What is not clear here to me, is -- why we need to define access rules for many different users and groups, and different actions instead of checking rights of only one current user and action? -- here in italics my main question is highlighted, just in case it may not so clear for readers (answer authors).
This code is executed in a context of specific request, for which a specific controller
, a specific action
, and a specific user
are already known. If, for example, the user is a guest, I don't see any reason to define rules for "admin" role or authenticated users.
Reasoning:
After some elaboration I came up to the following implementation:
public function accessRules()
{
return array(
array(Yii::app()->user->hasRights()?'allow':'deny'),
);
}
where hasRights
is a simple custom method added into a CWebUser
descendant:
class WebUser extends CWebUser
{
private $ACL = // ACL example
array('user' => // controller id
array('index' => User::AC_MODERATOR, // action ids
'view' => User::AC_MODERATOR,
'create' => User::AC_MODERATOR,
'update' => User::AC_ADMIN,
'delete' => User::AC_ADMIN,
'admin' => User::AC_ADMIN),
// ...
);
public function hasRights()
{
return (Yii::app()->user->getState('accessRights') >=
$this->ACL[Yii::app()->controller->id][Yii::app()->controller->action->id]);
}
}
As you may see, hasRights
uses current user "rights" (read from DB as usual), current controller and action to calculate single boolean true
or false
value as a decision about access.
What is wrong with this approach? Why Yii does not use something simple like that by default?
The Gii-generated accessRules
above do not only look excessive, but also imply that access rules are scattered among many controllers. In my approach a single and compact ACL is used.