AccessControl filter on parent and child controllers


#1

Hi, I am trying to restrict access to specific actions in my controllers using the AccessControl filter. I have a parent controller class which contains the logic for ensuring only authenticated users can access the controllers. Then in my child controller classes I have the logic to check whether the user is allowed to access specific actions. There is simply an integer field in the user’s table which specifies their access level.

BaseController:

class BaseController extends Controller
{
    public function behaviors()
    {
        return [
            'access' => [
                'class' => AccessControl::className(),
                'rules' => [
                    [
                        'allow' => true,
                        'roles' => ['@'],
                    ],
                ],
                'denyCallback' => function($rule, $action) {
                    return Yii::$app->user->loginRequired();
                },
            ],
            'verbs' => [
                'class' => VerbFilter::className(),
                'actions' => [
                    'delete' => ['POST'],
                ],
            ],
        ];
    }
}

CmsController:

class CmsController extends BaseController
{
    public function behaviors()
    {
        return ArrayHelper::merge(parent::behaviors(), [
            'access' => [
                'class' => AccessControl::className(),
                'rules' => [
                    [
                        'allow' => true,
                        'actions' => ['create', 'delete'],
                        'roles' => ['@'],
                        'matchCallback' => function($rule, $action) {
                            return Yii::$app->user->identity->access_level == 1;
                        },
                    ],
                    [
                        'allow' => true,
                        'actions' => ['index', 'view', 'update'],
                        'roles' => ['@'],
                        'matchCallback' => function($rule, $action) {
                            return Yii::$app->user->identity->access_level <= 3;
                        },
                    ],
                ],
            ],
        ]);
    }
}

However I found that this doesn’t work correctly, for example a user with access_level <= 3 can still access the create and delete actions.

Anybody know what is wrong with this code?


(demonking) #2

It’s the correct behaviour.
See this line

matchCallback function:

matchCustom will return true, because your “matchCallback” is not empty and your condition
would be true for all user with access_level <= 3.

Then the last check from the “if”

 return $this->allow ? true : false;

that’s also true, so the user is allowed to call this actions :slight_smile:

Solution would be, to set “allow” to false, then user with <=3 not allowed to call this action


#3

@demonking thanks but that did not work. Setting allow to false did not make any difference.

Interestingly my code works as expected if I replace ArrayHelper::merge with array_merge - so this must be something to do with the ArrayHelper::merge function.