Product.supplierID = Supplier.supplierID
--------- ----------
|Product|---------|Supplier|
--------- ----------
|
| Supplier.supplierID = User.supplierID
|
---------
| User |
---------
使用上面的表结构,应用程序使用ActiveController
的子类,重载prepareDataProvider
来限制每个index
列表Product
登录的 User
可以查看具有匹配 supplierID
值的那些。 ProductController
的 actions()
方法中有这样的内容。
$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()
来限制单个 Product
的 actionView()
。
目前,登录的 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
, update
和 view
操作将调用 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/