关于 c#:MVC 视图中的安全性

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 只渲染它。 (您使用的布尔属性就足够了)