Security in MVC Views
在我的 MVC 应用程序中,我有几个不同的角色:管理员、一般用户等。
我知道我可以通过 Authorize 属性为我的控制器应用安全性:
1 2 3 4 5 | [Authorize(Roles="Admin")] public ActionResult Create() { return View(); } |
但我还需要对视图应用一些安全性,以不将视图的某些部分显示给某些角色:
1 2 3 4 | @if( User.IsInRole("Admin") ) { @Html.ActionLink("Create","Create") } |
是按照上面的方式做,还是在 ViewModel 中处理这种安全性更好:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public ActionResult Index() { var model = new IndexViewModel(); model.CanCreate = User.IsInRole("Admin"); return View(model); } View: @( Model.CanCreate ) { @Html.ActionLink("Create","Create") } |
与第一种方法相比,第二种方法有什么好处吗?还是只是一种偏好?
第二种方式更受欢迎,因为您的业务逻辑将停留在模型级别。
在您的示例中,业务逻辑非常简单。但是,想象一下要求已经改变,现在不仅管理员可以创建内容,而且 1 个多月前注册的普通用户也可以创建内容。考虑到业务逻辑,您必须更新所有视图。
我之前做过的一种方法是创建一个从 AuthorizeAttribute 继承的操作过滤器。过滤器可以称为 DisplayIfAuthorizedAttribute,除了标准的 AuthorizeAttribute 属性外,还有一个名为 ViewNameIfNotAuthorized 的属性。
属性调用base方法进行授权,如果失败,返回ViewNameIfNotAuthorized视图。否则,它允许操作方法正常进行。
然后您将通过操作方法渲染这些部分视图,并通过您的父视图中的 Html.RenderAction 或 Html.Action 调用操作方法。这些操作方法将使用该属性进行修饰。
您现在有一个标准化的方法来执行此操作,并且没有授权代码污染您的操作方法的内部。
这是过滤器的样子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | public class DisplayIfAuthorizedAttribute : System.Web.Mvc.AuthorizeAttribute { private string _ViewNameIfNotAuthorized; public DisplayIfAuthorizedAttribute(string viewNameIfNotAuthorized = null) { _ViewNameIfNotAuthorized = viewNameIfNotAuthorized; } public override void OnAuthorization(AuthorizationContext filterContext) { bool isAuthorized = base.AuthorizeCore(filterContext.HttpContext); if (!isAuthorized) { filterContext.Result = GetFailedResult(); } } private ActionResult GetFailedResult() { if (!String.IsNullOrEmpty(_ViewNameIfNotAuthorized)) { return new ViewResult { ViewName = _ViewNameIfNotAuthorized }; } else return new EmptyResult(); } } |
您的操作方法将被装饰为:
1 2 3 4 5 | [DisplayIfAuthorized("EmptyView", Roles="Admin")] public ViewResult CreateLink() { return View("CreateLink"); } |
你可能需要两者...
请注意,仅第二个并不安全,用户可能能够在浏览器地址栏中为 actionlink 构建 URL。因此,您绝对需要该属性来确保安全。
第二个问题更多的是用户友好性或 UI 设计。也许您希望用户能够单击创建,然后可以选择以不同方式登录。
检查您的控制器中的授权,并根据您的角色规则为视图准备 Viewmodel。
视图用于简单地显示数据。所以,imo,他们不必进行角色检查等。
所以用它应该有的数据准备 ViewModel 并让 View 只渲染它。 (您使用的布尔属性就足够了)