ASP.NET MVC:基于用户的访问动态呈现控件

时间:2013-12-04 19:04:45

标签: c# asp.net asp.net-mvc razor domain-driven-design

在我的应用程序中,我有两个角色:管理员和用户。管理员可以分配用户以允许他们对特定对象执行特定功能。

由于这超出了SimpleMembership Roles可以提供的范围,我有一个静态帮助方法来检查用户是否有权访问特定的函数:

public static class SecurityCheck
{
    public static bool UserHasAccess(int objectId, string functionName)
    {
        // Decorates the security provider -- gets logged in User ID and calls to a repository to query the database
        // ...
    }
}

然后我可以在我的视图中使用它来确定是否应该根据对象的ID为该用户呈现特定的函数:

@foreach (var item in Model.FooData)
{
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.Name)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Notes)
        </td>
        <td>
            @Html.ActionLink("View Data", "View", new { @id = item.Id })
            @if (SecurityCheck.UserHasAccess(item.id, "Edit Data"))
            {
                @Html.ActionLink("Edit Data", "Edit", new {@id = item.Id})
            }
            @if (SecurityCheck.UserHasAccess(item.id, "Delete"))
            {
                @Html.ActionLink("Delete", "Delete", new {@id = item.Id})
            }
        </td>
    </tr>
}

我必须相信有更好的方法可以做到这一点,因为对静态方法的每个单独调用都涉及到数据库的单独往返,但我仍然坚持放置代码的最佳位置。我考虑过一些想法:

  1. 向我的ViewModels添加方法以将函数列表传递到存储库,返回用户可以为每个对象执行的函数列表。进一步思考这个问题,我甚至不确定这是否可能,就像它一样丑陋。
  2. 让ViewModel保持愚蠢,让我的应用层服务获取可用的功能。这将涉及向我的域模型对象添加其他属性,我并不疯狂。
  3. 创建一个可以从控制器调用的单独服务,该控制器可以将函数列表填充到ViewModel。这将涉及将多个服务注入每个控制器 - 对此也不是很疯狂。
  4. 我倾向于#2。但我仍然觉得我忽略了一个更加坚实的实施。有没有人以前处理类似的事情?

2 个答案:

答案 0 :(得分:3)

我认为每个ViewModel都“知道”可以用它做什么,不是吗?所以我们可以隐式显式。 ViewModel可以显式具有CanEdit,CanDelete等属性。

用户界面不应该关心为什么允许或不允许某些操作,它只是以某种方式检查这些属性:

@if (item.CanEdit)
{
   @Html.ActionLink("Edit Data", "Edit", new {@id = item.Id})
}

你甚至可以拿出一个帮助器,它将另一个boolean作为参数来决定是否应该渲染(或启用)控件,但它是次要的:

@Html.SecureActionLink(item.CanEdit, "Edit Data", "Edit", new {@id = item.Id})

这个想法是,UI的责任是知道如何根据某些业务规则判断是否允许某些内容。 但肯定UI有责任知道在一个ViewModel中呈现的方式和内容不是Editable或另一个是ReadOnly(不同的东西可以有不同的状态)。

此外,由于我们正在谈论DDD,我建议不要建模CRUD操作。在一天结束时,DDD是关于无处不在的语言,“创建,更新,删除”几乎不是语言业务真正说的。

因此,您最终会在模型中获得更精确,更有意义的属性/操作,例如CanAccept(针对订单屏幕)或“CanMakeRefund”(针对付款)。

在构建ViewModel并对其应用安全上下文时,您可以解析/设置这些属性。

希望它有所帮助。

答案 1 :(得分:0)

也许您需要使用SimpleMembership角色:

Assigning Roles with MVC SimpleMembership

在标准MVC会员资格中,您可以使用以下内容:

Roles.AddUserToRole(model.UserName, "Admin");

在你身上查看例如:

if (ViewContext.HttpContext.User.IsInRole("Admin"))