2011-05-05 77 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上。明显的缺点是,你仍然可以忘记把你的安全检查。使用某种依赖注入也会使这个更好。

相关问题