2011-05-05 130 views
6

我在我的_Layout.cshtml中使用@RenderSection("Contextual", false)允許不同的視圖來呈現他們的特定內容。有些沒有,有些則是。隱藏Html.ActionLinks基於角色的安全

此外,我使用基於角色的安全性和ActionFilter來控制特定用戶是否有權訪問特定的控制器操作,從而訪問我的站點上的路由。

我想要做的就是提供我_Layout.cshtml一個@RenderSection("Contextual", false)部分,然後有特定頁面提供力所能及的上下文的東西是有道理的,那頁有相應的控制器處理的用戶是否審批可以執行一個動作,甚至可能看到選項存在,但我不確定我是否正確地考慮此問題。這裏的事情是如何目前:

現在我已經得到了部分的我Index.cshtml文件中的一個,像這樣:

@section Contextual { 
    <div>@Html.ActionLink("Create New", "Create")</div> 
    <div>@Html.ActionLink("Generate Report", "Report")</div> 
    <div>@Html.ActionLink("Other Stuff", "Other")</div> 
} 

,然後在我的相應的控制器,我已經得到的東西,像這樣:

[Authorize(Roles = "Editor")] 
public ActionResult Create() 
{ 
    // stuff 
} 

這將按我的意願工作(非編輯者不會創建新項目),但創建條目是所有人都可以看到的。我可以做一些像這樣:

@section Contextual { 
    @if (User.IsInRole("Editor")) 
    { 
    <div>@Html.ActionLink("Create New", "Create")</div> 
    } 
    <div>@Html.ActionLink("Generate Report", "Report")</div> 
    <div>@Html.ActionLink("Other Stuff", "Other")</div> 
} 

這工作得很好,隱藏創建從非編輯聯繫,但我在籬笆它是否是好還是不這樣處理加我我可以看到,在規則發生變化的情況下,我有兩個位置保持同步:控制器操作的屬性和視圖中的代碼。

這是一個合理的方法嗎?有沒有更好的方法來解決這個問題?

回答

8

我喜歡在控制器上使用更明確的視圖模型標誌。

例如:

// on the controller 
viewModel.CanCrete = User.IsInRole("Editor"); 
// ...snip... 
return View(viewModel); 
} 

那麼,你就需要這個標誌在基類中的視圖模型添加到您的視圖模型或可能。你可以去創建一個Custom Action Filter的路徑來在多個控制器中填充它,或者在你的控制器基類中做一些處理。

我也喜歡來定義一個方便的擴展方法:

public static string If(this string s, bool condition) 
{ 
    return condition ? s : String.Empty; 
} 

取決於哪些API你使用,你也可能需要延長MvcHtmlString

然後在視圖:

@section Contextual { 
    <div>@Html.ActionLink("Create New", "Create").If(Model.CanCrete)</div> 
    <div>@Html.ActionLink("Generate Report", "Report")</div> 
    <div>@Html.ActionLink("Other Stuff", "Other")</div> 
} 

你可以決定你想這樣做對div什麼,你可能希望有另一個幫手包裹在div的鏈接,或者你可以使用CSS來實現無論您想要的視覺佈局如何。

+0

感謝您的回覆。我猜你對解決方案的看法是,用戶角色檢查在控制器中完成,然後View真的沒有得到擔心*爲什麼創建功能被啓用/禁用的業務 - 將信息。允許在控制器端使用許多原因來翻轉CanCreate位。好東西。我*絕對*喜歡這種擴展方法 - 它*是*方便。 :) – itsmatt 2011-05-07 00:23:29

+0

@itsmatt沒問題。我正在研究的當前系統充滿了基於(上下文+角色)的安全性,因此很多時候都會遇到這種情況。我認爲你打上了關鍵點,從控制器中分離了觀點的顧慮。另一條路線可能是根據角色生成鏈接列表(也可以在控制器中填充) – TJB 2011-05-07 07:12:12

0

我喜歡@ TJB的回答很多,並且認爲我實際上會做類似的事情。但是,如果您想要採用不同的路線......您可以創建自己的LinkExtensions,從而使標準的LinkExtensions超載。

public static class MyLinkExtensions 
{ 
    public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, YourAccessStuff access) 
    { 
     if(access.Has(actionName)) 
     { 
      ActionLink(htmlHelper, linkText, actionName);    
     } 
     else 
     { 
      // Maybe only show the link text as if it's disabled and not a link? 
      // Maybe do nothing?   
     } 
    } 
} 

這裏假設「YourAccessStuff」實際上已經實現。這將集中這些訪問檢查,而不是將它們粘在每個ActionLink上。明顯的缺點是,你仍然可以忘記把你的安全檢查。使用某種依賴注入也會使這個更好。