2017-05-17 56 views
0

我正在一個有多層安全性的網站上工作。最基本的安全級別由驗證用戶身份是否正確的自定義授權屬性來處理。對於API上的細粒度授權,哪種方法是正確的授權方法?

我們使用Authorize方法在控制器中裝飾方法,這可以防止未經授權的用戶訪問這些調用。

但是,我們也有一些細粒度的權利要求。例如,來自公司A的用戶不應該能夠修改來自公司B的任何用戶。因此,儘管A公司和B公司的管理員都有權從API調用「UpdateUser」,但公司A不應該更新公司B的用戶之一。

目前,控制器內部正在處理跨公司訪問的限制。我遇到的問題是,我們介紹的每種新方法都包括代碼的複製和粘貼,或者包含非常類似的變體。

這就是說,我不確定它是否屬於服務(我們稱之爲UserService)。

所以選擇我已經有:

  1. 執行控制器內部檢查,看是否請求更新的用戶是同一家公司的一部分,爲使用者更新

  2. 執行在服務內部進行相同的檢查。

  3. 來自社區的任何建議。

第二種方法的優點是代碼不需要在控制器中重複。當多個控制器調用相同的服務方法時,好處很明顯 - 底層的檢查是一致的,代碼不會重複。

第二種方法的缺點是,現在我的服務需要知道已認證的用戶。這給單元測試帶來了一些問題。

對於這些細粒度權利類型,哪些模式被認爲是「最佳實踐」?

回答

0

TLDR;我個人只是保持訪問檢查的行動。你總是可以嘗試用其他功能和lambda表達式喜歡泛化它:

return IfAccessIsGood("CompanyA","anotherparam",()=>{ /* do something */ }); 

但這裏是我的我原本放在一起爲你全響應:

這聽起來像你有在控制器內更改參數行動是指定的公司和您基於公司,像執行您的訪問檢查:

[AuthorizeCustom] 
[Route("{company}/{something}")] 
[HttpPost] 
public async Task<IHttpActionResult> DoSomething(string company, string something) { 
    if(company == "A" && something == "NOTA") 
    { 
     return BadRequest("Your company can't do that!!!"); 
    } 
    else if(company == "B" && something == "NOTB") 
    { 
     return BadRequest("Your company can't do that!!!"); 
    } 
    else {} // do the thing 
} 

顯然你的實現可能看起來很多更優雅,但我猜想它是做引擎蓋下類似的東西。

如果公司訪問從根本上必須被區別對待,您可以創建一個基類繼承ApiController並將CompanyA和CompanyB實現的基類實現爲您的控制器,這將使它們完全分離。然後,您可以重寫一個Access函數來檢查訪問,併爲暴露的API實現每種方法。你的路由將不再是可變的,併成爲:

[路線( 「公司A/{事}」)]

[路線( 「CompanyB/{事}」)]

這些將分別位於在他們自己的繼承自Base的類中,因此可以讓你實現任何你需要的控制,而不必複製非常多的代碼。

這並變得棘手,因爲屬性不能被繼承(至少不是通過慣用的手段),但你可以這樣做:通過標準化的訪問,只是重寫屬性

[AuthorizeCustom] 
[RoutePrefix("CompanyA")] 
public class CompanyA : BaseClass 
{ 
    [Route("{something}")] 
    [HttpPost] 
    override async Task<IHttpActionResult> DoSomething(string something) { return await base.DoSomething(something); } 

    override bool CheckAccess(string something) { 
    if(something != "A") return false; 
    else return true; 
    } 
} 

你可以做這麼遠更優雅以獲取公司價值而不是重寫每個公司實施中的訪問權限,但這仍然不是一個好的解決方案,除非您可以通過重寫集中功能找到其他一些優勢。老實說,我可能只是在控制器動作本身中保持邏輯。如果你想輕鬆地進行單元測試,把行爲邏輯的核心放在其他地方,並簡單地在動作中返回它的值,這樣你就可以在一個單獨的函數/類中對99%的邏輯進行單元測試。