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

6
我在我的_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
}

这样做可以达到我的要求(非编辑人员无法创建新项目),但所有人都能看到“创建条目”的选项。我可以这样做:
@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个回答

8
我很喜欢在控制器上使用更明确的标志来填充视图模型。
例如:
 // on the controller
 viewModel.CanCrete = User.IsInRole("Editor");
 // ...snip...
 return View(viewModel);
}

因此,您需要将此标志添加到您的视图模型中,或者可能是在视图模型的基类中。您可以创建一个自定义操作筛选器来在多个控制器中填充它,或者在控制器基类中进行一些处理。

我还喜欢定义一个方便的扩展方法:

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,你可能想要创建另一个帮助程序将链接包装在
中,或者你可以使用CSS来实现任何你想要的视觉布局。

感谢回复。我想我喜欢您的解决方案的原因是用户角色检查在控制器中完成,视图实际上不需要关心为什么“创建”功能已启用/禁用-将该信息分离出来。允许在控制器端使用任意数量的原因来翻转CanCreate位。好东西。我绝对喜欢那个扩展方法 - 它真的很方便。 :) - itsmatt
@itsmatt 没问题。我正在处理的当前系统充满了基于(上下文+角色)的安全性,因此经常遇到这种情况。我认为你提到了关键点,即将视图的关注点与控制器分离。另一种方法可能是根据角色生成链接列表(也可以在控制器中填充)。 - TJB

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上。显然的缺点是你仍然可能忘记放置安全检查。使用某种依赖注入也会使这更好。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接