即使从具有 Yii2 行为的 matchCallback 返回 false 时也设置自定义 denyCallback

Setting custom denyCallback even when returning false from matchCallback with Yii2 behaviours

我正在使用 Yii2 并在我的控制器中使用它们的 behaviors

我正在构建自己的权限系统,由于权限相当复杂,我需要使用 matchCallback.

这是一个例子:

public function behaviors() {
    return [
        'access' => [
            'class' => AccessControl::className(),
            'only' => ['view'],
            'rules' => [
                [
                    'allow' => true,
                    'actions' => ['view'],
                    'matchCallback' => function ($rule, $action) {
                        return Yii::$app->authManager->can($rule, $action);
                    }
                ],      
                // everything else is denied
            ],
        ],
    ];
}   

现在,不幸的是 matchCallback 的工作方式是 returning truefalse 是否应该 continue 来执行规则,而不是能够 return 是否允许或不允许。

所以如果我 return false 它不应该继续(因此不允许它们)那么我无法自定义 denyCallback 因为它退出执行规则。

我是否可以自定义 denyCallback,即使我从 matchCallback return false - 或者我应该以不同的方式处理我的情况?

您可以将 denyCallback 定义为 AccessControl 的 属性 而不是在 AccessRule 中定义它。如果 allow 在规则检查 returns null 之后,它将被调用。它与 AccessRule 中的 denyCallback 具有相同的签名:

public function behaviors() {
    return [
        'access' => [
            'class' => AccessControl::className(),
            'only' => ['view'],
            'rules' => [
                [
                    'allow' => true,
                    'actions' => ['view'],
                    'matchCallback' => function ($rule, $action) {
                        return Yii::$app->authManager->can($rule, $action);
                    }
                ],
            'denyCallback' => function ($rule, $action){...}
            // everything else is denied
            ],
        ],
    ];
}  

作为另一种选择,您可以扩展 AccessRule class 并将 allows() 方法覆盖为 return false 而不是 null 当匹配检查失败时,您的规则 denyCallback 将被调用:

class MyAccessRule extends AccessRule
{
    public function allows($action, $user, $request)
    {
        $allows = parent::allows($action, $user, $request);
        if ($allows === null) {
            return false;
        } else {
            return $allows;
        }

    }
}

matchCallback 只判断是否应用规则,如果 matchCallback returns true 和其他参数匹配(例如rolesverbs 等),调用 allows() 将 return 规则的 allow 参数 truefalse 在配置中设置。如果 matchCallback returns false - allow 将是 null 并且规则的 denyCallback 将不会被调用,但如果在配置中设置了 AccessControl denyCallback,则会被调用。

正如您在评论中提到的,第三个选项是使 allows() return 回调结果。

class MyAccessRule extends AccessRule
{
    public $allowCallback;
    public function allows($action, $user, $request)
    {
        if(!empty($this->allowCallback) {
            return call_user_func($this->allowCallback);
        }
        $allows = parent::allows($action, $user, $request);
        if ($allows === null) {
            return false;
        } else {
            return $allows;
        }

    }
}

嗯...使用 Yii::$app->authManager->checkAccess($uerId,$permissionName,$dataToPassInArray) 非常简单 then.If 你想要当前登录用户的 id,你应该通过 Yii::$app->user->identity 在 first.Properties 获取当前用户的实例登录用户实例取决于您使用的用户模型(例如 yii\web\User 或其他自定义模型)。