Manually check if user has access to a Controller and an Action *SOLVED*

Hi,

I’m writing a CMS that is setup as a module. Seperate parts of the CMS are setup as seperate Controllers, and each controller has filters for accessRules where I can decide who gets access to that controller and it’s actions based on their access.

So, as per usual in my Controller, I have it setup like so:


    

public function accessRules() {

   return array(

            array('allow', // no one can create, update, or delete these:

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

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

                'expression' =>

                'isset(Yii::app()->user->usertype_id) && ' .

                'Yii::app()->user->usertype_id <= UserTypesModel::USERTYPES_ADMIN '

            ),

            array('deny', // deny all users anything not specified

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

            ),

        );

}



This works perfectly, so I can easily assign different user access depending on their usertype. But I’d like to use this to help decide which menu items are shown.

I’ve used the metadata class to help draw a menu based on the Controllers that exist within the module. But I’d like to extend this to make it only show the controllers that the current user has access to, based on the filters I’ve setup as above.

Is there any way I can instantiate a controller and manually run the accessRules to get a true or false on whether or not a user has access to it?

Something like:




$controller = new MyController();

$hasAccess = $controller->hasAccess(Yii::app()->user);

if ($hasAccess) { 

 // You can use access this part of the CMS

} else {

  // You can't use this part of the CMS

}



So, is this possible?

Thanks in advance.

Is too difficoult to use the rules, I’d better repeat the expression in CMenu

I wanted to avoid handcoding the menu, which is why I used the metadata plugin to show me all the controllers. BUT- your idea of using CMenu led me to use the visible flag!

I have come up with a solution… I use the metadata plugin to get all the controllers, then loop through them to add them to a menu which is used by CMenu. I also use Yii’s CComponent::evaluateExpression to evaluate the filter I want, which I then use to define the visible flag in the menu items.




// Use the Metadata helper to load the Modules known Controllers

$arr_Controllers = Yii::app()->metadata->getControllers($str_ModuleName);


foreach($arr_Controllers as $str_Controller):


    // Instantate the Controller

    $obj_Controller = new $str_Controller($str_Controller);


    // Get the Controllers accessRules

    $arr_accessRules = $obj_Controller->accessRules();


    // Get the expression we want to compare (always the first rule)

    $str_Expression = $arr_accessRules[0]["expression"];


    // Use Yii's CComponent::evaluateExpression to evaluate the accessRule

    $bool_IsVisible = CComponent::evaluateExpression($str_Expression);


    // Setup the array for used with zii.widgets.CMenu

    $arr_MenuOption_Temp = array();

    $arr_MenuOption_Temp["label"] 

        = str_replace("Controller", "", $str_Controller);

    $arr_MenuOption_Temp["url"] 

        =  array("/". $str_ModuleName . "/". strtolower($arr_MenuOption_Temp["label"]));       

    $arr_MenuOption_Temp["visible"] 

        = $bool_IsVisible;      

    $arr_MenuOption_Temp["active"] 

        = (substr_count(Yii::app()->getRequest()->url, strtolower($arr_MenuOption_Temp["url"])) > 0);


    // Add the menu item to the array

    $arr_MenuOptions[] = $arr_MenuOption_Temp;


endforeach;



And then in a view, all I do is this to use it:




$this->widget('zii.widgets.CMenu', array('items'=>$arr_MenuOptions));



I would cache the code once completed, as I don’t think it’s particularly well optimized yet, but this does the job.

It uses the same filter rules that would normally be used - but I don’t have to manually create a menu every time I implement the CMS. It simply draws the menu based on the Controllers available and the access that the user has to them.

Of course, I’m open to corrections or improvements! Please let me know.

sounds good.

it’s a creative idea that you follow but you know it may in a project or this cms you have lots of controller in some module so if why you do not use rbac in your project you can define the access to module and controllers in database and get the access to that with just a simple query that can be a cached one!

and one more things here you can find a good method http://webscriptz.be/2011/02/16/yii-framework-rbac/369 to store informatin in database