2015-10-16 31 views
5
Product.supplierID = Supplier.supplierID 
---------   ---------- 
|Product|---------|Supplier| 
---------   ---------- 
         | 
         | Supplier.supplierID = User.supplierID 
         | 
        --------- 
        | User | 
        --------- 

使用上述表結構,該應用程序使用的子類的ActiveController,與重寫prepareDataProvider限制每個ProductUser一個登錄的index列表可以看到的那些具有匹配supplierID值。 方法ProductController中的這種情況。Yii2 - 覆蓋的checkAccess在休息ActiveController

$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()限制actionView()單個Product

目前,在User一個記錄可以通過改變在URL中productID訪問Product中,是否擁有相應的supplierID

它看起來像我不能訪問Product的特定實例,檢查supplierID,直到actionView()已返回,這是我希望檢查發生時。

我可以覆蓋checkAccess()限制訪問並拋出相應的ForbiddenHttpException

+0

所以,你想禁止從產品ID訪問URL。 –

+0

嗯,也許?沒有從這個方向想到它。更多的是考慮不返回不允許的數據,但可能會有一個解決方案,將'productID'作爲'GET'參數。一定要考慮一下... –

回答

4

怎麼樣來檢查,如果模型中存在的函數:

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

如果productID是你的產品主鍵,然後/products/1的請求將被警予\休息翻譯\ UrlRule/products?productID=1

在這種情況下,當productIDPARAM提供,你可以使用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; 
} 

更新

由於問題是關於重寫在休息checkAccess方法ActiveController我認爲留下一個例子會很有用。一旦模型實例加載

在Yii2 REST是如何設計的方式,所有的deleteupdateview行動將調用checkAccess方法:

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

同樣是爲createindex真除了他們不會傳遞任何模型實例: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.'); 
     } 

    } 
} 
+0

@SalemOerdany;這與我目前使用的輔助方法(不是'checkAccess')適合地引發自定義'actionMethods'並在每個重寫的「action」方法的頂部調用方法類似。儘管如此,你的解決方案會讓人感覺更具有慣性。我要給你的想法一個去,並會報告回來。謝謝 –

+0

不客氣。在執行或使用之前,我一直將[checkAccess](http://www.yiiframework.com/doc-2.0/guide-rest-controllers.html#performing-access-check)方法看作處理授權的適當位置任何行動。 –

+0

這個解決方案與我一起構建嵌套的資源路由,如[這裏](https://github.com/yiisoft/yii2/issues/9474)所述,並且在IndexAction中實現過濾之後,如[here]所示(http:// stackoverflow .COM /問題/ 25522462/yii2休息查詢#答案-30560912)。我的完整代碼是[this](https://github.com/tunecino/Yii2_foundation-apps/blob/master/backend/api/modules/v1/controllers/ImageController.php),它工作正常,但我也跟着你的問題,因爲我也有不同的方式來解決它,尤其是在你提到checkAccess方法後。 –