Search code examples
yiiyii2yii2-advanced-appyii2-basic-appyii2-validation

Yii2. Access control by roles. How can I add 'OR' condition?


I have a controller with the following access restriction:

'access' => [
                'class' => AccessControl::className(),
                'only' => ['index', 'view', 'create', 'update', 'delete'],
                'rules' => [
                    [
                        'actions' => ['index', 'view'],
                        'allow' => true,
                        'roles' => [RbacComponent::VIEW_EXPENSES_ACCOUNTS_KEY],
                    ],
                    [
                        'actions' => ['create'],
                        'allow' => true,
                        'roles' => [RbacComponent::CREATE_EXPENSES_ACCOUNTS_KEY],
                    ],
                    [
                        'actions' => ['update'],
                        'allow' => true,
                        'roles' => [RbacComponent::EDIT_EXPENSES_ACCOUNTS_KEY],
                    ],
                    [
                        'actions' => ['delete'],
                        'allow' => true,
                        'roles' => [RbacComponent::DELETE_EXPENSES_ACCOUNTS_KEY],
                    ],
                ],
            ],

How can I add 'OR' \Yii::$app->user->identity->isOwner() to all that rules?

I tried to use this variant:

            [
                'actions' => ['index', 'view'],
                'allow' => true,
                'roles' => [RbacComponent::VIEW_EXPENSES_ACCOUNTS_KEY],
                'matchCallback' => function ($rule, $action) {
                    return \Yii::$app->user->identity->isOwner();
                }
            ],

But, in this case, it will be 'AND' and won't work.

I think this variant will work:

            'rules' => [
                [
                    'actions' => ['index', 'view', 'create', 'update', 'delete'],
                    'allow' => true,
                    'roles' => ['@'],
                    'matchCallback' => function ($rule, $action) {
                        if ($action == 'index') {
                           if (\Yii::$app->user->identity->isOwner() || \Yii::$app->user->can(RbacComponent::VIEW_EXPENSES_ACCOUNTS_KEY)) {
                              return true;
                          }
                        }

                        ... other actions

                    }
                ],

But maybe there is better and simpler way?


Solution

  • You could simply add a rule with your callback :

    'rules' => [
        [
            'actions' => ['index', 'view'],
            'allow' => true,
            'roles' => [RbacComponent::VIEW_EXPENSES_ACCOUNTS_KEY],
        ],
        [
            'actions' => ['create'],
            'allow' => true,
            'roles' => [RbacComponent::CREATE_EXPENSES_ACCOUNTS_KEY],
        ],
        [
            'actions' => ['update'],
            'allow' => true,
            'roles' => [RbacComponent::EDIT_EXPENSES_ACCOUNTS_KEY],
        ],
        [
            'actions' => ['delete'],
            'allow' => true,
            'roles' => [RbacComponent::DELETE_EXPENSES_ACCOUNTS_KEY],
        ],
        [
            'actions' => ['index', 'view', 'create', 'update', 'delete'],
            'allow' => true,
            'matchCallback' => function ($rule, $action) {
                return \Yii::$app->user->identity->isOwner();
            },
        ],
    ],