设置自定义denyCallback,即使在Yii2行为的matchCallback返回false时也是如此


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

我正在使用Yii2,并在我的控制器中利用它们的行为。

我正在构建自己的权限系统,因为权限相当复杂,我需要使用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的工作方式是返回truefalse,而不是返回允许或不允许的true或false。

因此,如果我返回false,它不应该继续(因此不允许它们(,那么我就无法自定义denyCallback,因为它退出了执行规则。

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

您可以将denyCallback定义为AccessControl的属性,而不是在AccessRule中定义它。如果allow在规则检查后返回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类并覆盖allows()方法以返回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返回true并且其他参数匹配(例如角色动词等(,则在配置中设置时,对allows()的调用将返回规则的allow参数truefalse。如果matchCallback返回false-allow将为null并且不会调用规则的denyCallback,但如果在配置中设置了AccessControldenyCallback,则会调用它。

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

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;
        }
    }
}

嗯。。。那么使用CCD_ 27是相当简单的。如果您想要当前登录用户的id,首先应该通过Yii::$app->user->identity获取当前用户的实例。已登录用户实例的属性取决于您使用的用户模型(例如yii'web'User或其他自定义模型(。