基于基于角色的安全性隐藏Html.ActionLinks

时间:2011-05-05 17:46:51

标签: asp.net asp.net-mvc asp.net-mvc-3 roles

我在_Layout.cshtml中使用@RenderSection("Contextual", false)来允许不同的视图在其中呈现其特定内容。有些人没有,有些则没有。

此外,我使用基于角色的安全性和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
}

这将按我的意愿工作(非编辑不会创建新项目),但Create条目可供所有人查看。我可以这样做:

@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>
}

这样做效果很好,隐藏了非编辑的创建链接,但是我已经开始关注是否以这种方式处理它是好的加上我可以看到我已经得到了规则发生变化的情况,然后我有两个位置保持同步:控制器操作的属性和视图中的代码。

这是一种合理的方法吗?有没有更好的方法来解决这个问题?

2 个答案:

答案 0 :(得分: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来实现你想要的任何视觉布局。

答案 1 :(得分: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上。显而易见的缺点是你仍然可以忘记进行安全检查。使用某种依赖注入也可以使这更好。