php - Yii2 - 在其余 ActiveController 中覆盖 checkAccess

标签 php yii yii2

Product.supplierID = Supplier.supplierID
---------         ----------
|Product|---------|Supplier|
---------         ----------
                       |
                       |  Supplier.supplierID = User.supplierID
                       |
                   ---------
                   |  User |
                   ---------

使用上面的表结构,应用程序使用ActiveController的子类,重载prepareDataProvider来限制每个index列表Product 登录的 User 可以查看具有匹配 supplierID 值的那些。 ProductControlleractions() 方法中有这样的内容。

$actions['index']['prepareDataProvider'] = function($action)
{
    $query = Product::find();
    if (Yii::$app->user->can('supplier') &&
        Yii::$app->user->identity->supplierID) {
        $query->andWhere(['supplierID' => Yii::$app->user->identity->supplierID]);
    }
    return new ActiveDataProvider(['query' => $query]);
};

这工作正常,但我希望使用 checkAccess() 来限制单个 ProductactionView()

目前,登录的 User 可以通过更改 URL 中的 productID 来访问 Product,无论是否有适当的 supplierID

看起来我无法访问 Product 的特定实例来检查 supplierID,直到 actionView() 返回是我希望进行检查的时间。

我可以覆盖 checkAccess() 来限制访问并抛出适当的 ForbiddenHttpException 吗?

最佳答案

检查模型是否存在的函数怎么样:

protected function modelExist($id)
{
    return Product::find()
    ->where([ 'productID' => $id ])
    ->andWhere(['supplierID' => Yii::$app->user->identity->supplierID ])
    ->exists(); 
}

如果productID是您的产品主键,然后请求 /products/1将被 yii\rest\UrlRule 翻译成 /products?productID=1 .

在那种情况下,当productID作为参数提供,您可以使用beforeAction快速检查此类模型是否存在并执行操作,如果不存在则抛出错误:

// this array will hold actions to which you want to perform a check
public $checkAccessToActions   = ['view','update','delete'];

public function beforeAction($action) {
    if (!parent::beforeAction($action)) return false;

        $params = Yii::$app->request->queryParams;

        if (isset($params['productID']) {
           foreach ($this->checkAccessToActions as $action) {
              if ($this->action->id === $action) {
                  if ($this->modelExist($params['productID']) === false)
                       throw new NotFoundHttpException("Object not found");
              }
           }
    }
    return true;
}

更新

由于问题是关于重写 rest ActiveController 中的 checkAccess 方法,我认为留下一个例子会很有用。

在 Yii2 REST 的设计方式中,所有 delete , updateview操作将调用 checkAccess加载模型实例后的方法:

// code snippet from yii\rest\ViewAction
$model = $this->findModel($id);
if ($this->checkAccess) {
    call_user_func($this->checkAccess, $this->id, $model);
}

create也是如此和 index除了它们不会将任何模型实例传递给它之外的操作:call_user_func($this->checkAccess, $this->id) .

所以您尝试做的事情(当用户试图查看、更新或删除不是其供应商的产品时抛出 ForbiddenHttpException)也可以通过以下方式实现:

public function checkAccess($action, $model = null, $params = [])
{
    if ($action === 'view' or $action === 'update' or $action === 'delete') 
    {
        if ( Yii::$app->user->can('supplier') === false
             or Yii::$app->user->identity->supplierID === null
             or $model->supplierID !== \Yii::$app->user->identity->supplierID ) 
        {
             throw new \yii\web\ForbiddenHttpException('You can\'t '.$action.' this product.');
        }

    }
}

关于php - Yii2 - 在其余 ActiveController 中覆盖 checkAccess,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33168784/

相关文章:

php - Laravel 5 UnexpectedValueException 响应

javascript - : How To Have Ajax Validation On A Part Of The Form Showed With An Ajax Event And A Renderpartial? yii

Yii:如何强制 CGridview 仅通过 AJAX 加载数据?

php - 如何设置参数在未设置时不过滤SQL查询

php - 使用 SimpleXML 读取 RSS 提要

php - 如何在yii2的gridView中创建自定义ActionColumn?

yii2 - 在DetailView小部件中更改属性的值

php - 在 Yii2 中使用 MySQL "IN"语法绑定(bind)参数的正确方法?

php - 目录请求时出现身份验证错误 (SE2000)。 iDEAL支付网关

php - Yii:使 dropDownList 只读/禁用形式