Yii2 RBAC - Permissions in Controller Behaviors

How to set up RBAC within a Controller::behaviors() method, such that a User’s Permissions are checked for certain Actions?

Basically, this same question from Stack Overflow:

Ive been at it all night, and I cant seem to configure Controller::behaviors() in any way as to simply read a given Permission for a given Action against the current User. It seems to be the only way I can enforce the subtleties of the RBAC implementation as found in the Yii2 Guide is by adding lots of conditionals to my code:


if (\Yii::$app->user->can('updateOwnPost')) {

    // continue through current controller action...

} else {

    // do the deny access routine that should probably just be handled in $this->behaviors();

}

Can someone demonstrate a robust configuration for a controller behaviors() ‘access’ component, that demonstrates the RBAC example from the Yii Guide? Reading the source code hasnt revealed to me how this is done.




                'rules' => [

                    [

                        'allow' => true,

                        'actions' => ['youraction',],

                        'roles' => ['updateOwnPost'],

                    ],




Well, there’s good news and there’s bad news.

The bad news is I don’t think that other post really deals with the type of permission of ‘updateOwnPost’, as you would need to retrieve the record to see if it’s owned or not. Where you don’t need to retrieve the model, Misbahul’s answer is perfectly fine. However if you do actually need to do a check against the ActiveRecord model, this won’t work.

Edit below:

You can however, be a little bit cheeky and fetch the model via the app controller within the ‘updateOwnPost’ rule. In my application, I’ve made it more generic so that I have a basic ‘ownerRule’ which can be applied to any type of record.

In the controller:




                   'rules' => [

                        [

                        'allow' => true,

                        'actions' => ['view'],

                        'roles' => ['viewRequest'],

                        ]

                    ]



In the RBAC init script:




        $auth       = Yii::$app->authManager;

        

        //Create two roles to work with

        $basic      = $auth->createRole('basic');

        $admin      = $auth->createRole('admin');


        $auth->add($basic);

        $auth->add($admin);

 

        //Create the owner only override

        $ownerOnly = new \frontend\rbac\OwnerRule;

        $auth->add($ownerOnly);


        //View all

        $viewRequest = $auth->createPermission('viewRequest');

        $viewRequest->description = 'View request';

        $auth->add($viewRequest);


        //View own only

        $viewOwnRequest = $auth->createPermission('viewOwnRequest');

        $viewOwnRequest->description = 'View Own Request';

        $viewOwnRequest->ruleName = $ownerOnly->name;

        $auth->add($viewOwnRequest);


        $auth->addChild($basic,$viewOwnRequest); //Basic can view own.

        $auth->addChild($viewOwnRequest,$viewRequest); //When view all fails, check for view own

        $auth->addChild($admin, $viewRequest); //Admin can view all.




And in the OwnerRule class:




namespace frontend\rbac;


use yii\rbac\Rule;

use yii;


class OwnerRule extends Rule {


    public $name = 'isOwner';


    /**

     * @param string|integer $user the user ID.

     * @param Item $item the role or permission that this rule is associated with

     * @param array $params parameters passed to ManagerInterface::checkAccess().

     * @return boolean a value indicating whether the rule permits the role or permission it is associated with.

     */


    public function execute($user, $item, $params)

    {

        if(isset($params['model'])){ //Directly specify the model you plan to use via param

            $model = $params['model']; 

        }else{ //Use the controller findModel method to get the model - this is what executes via the behaviour/rules

            $id = Yii::$app->request->get('id'); //Note, this is an assumption on your url structure.

            $model = Yii::$app->controller->findModel($id); //Note, this only works if you change findModel to be a public function within the controller.

        }

        return $model->created_by == $user;

    }


}



Thanks I managed to find a similar workaround. At this point, Ive spent more time aimlessly trying to figure out Yii2’s idioms than I have actually programming and getting work done!

RBAC is one of the few Yii2 unattended spots. Check how these devs approached the subject

Thanks again bis, Ill look into those if I have a need to revisit RBAC.