Yii2 - 覆盖休息ActiveController中的checkAccess

Ped*_*Sol 5 php yii yii2

Product.supplierID = Supplier.supplierID
---------         ----------
|Product|---------|Supplier|
---------         ----------
                       |
                       |  Supplier.supplierID = User.supplierID
                       |
                   ---------
                   |  User |
                   ---------
Run Code Online (Sandbox Code Playgroud)

使用上面的表结构,应用程序使用子类ActiveController,通过重写prepareDataProvider来限制index每个Product登录的列表User可以看到具有匹配supplierID值的列表.在actions()方法中有类似的东西ProductController.

$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]);
};
Run Code Online (Sandbox Code Playgroud)

这工作正常,但我希望checkAccess()用来限制actionView()单个Product.

此时,登录后User可以Product通过更改productIDURL 来访问a ,无论是否具有相应的supplierID.

看起来我无法访问特定的实例Product,检查supplierID,直到actionView()已经返回,这是我希望检查发生的时候.

我可以覆盖checkAccess()以限制访问并抛出相应的内容ForbiddenHttpException吗?

Sal*_*ani 5

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

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

如果productID是您的产品主键,则yii\rest\UrlRule/products/1会将请求转换为。/products?productID=1

在这种情况下,当productID作为param提供时,您可以使用它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;
}
Run Code Online (Sandbox Code Playgroud)

更新

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

在这样Yii2 REST是如何设计的,所有的deleteupdateview行动将调用checkAccess一旦模型实例调用的方法:

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

除了它们不会将任何模型实例传递给它之外,对于createindex动作也是如此:call_user_func($this->checkAccess, $this->id)

因此,您尝试执行的操作(当用户尝试查看、更新或删除不是其供应商的产品时抛出ForbiddenHttpException)也可以通过以下方式实现:

// 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;
}
Run Code Online (Sandbox Code Playgroud)