【问题标题】:ASP.NET MVC: Dynamically rendering controls based on user's accessASP.NET MVC:根据用户的访问动态呈现控件
【发布时间】:2013-12-04 19:04:44
【问题描述】:

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

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

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. 向我的 ViewModel 添加方法以将函数列表传递到存储库,返回用户可以为每个对象执行的函数列表。进一步考虑这一点,我什至不确定这是否可能,尽管它会很丑陋。
  2. 让 ViewModel 保持不变,让我的应用层服务获取可用功能。这将涉及向我的域模型对象添加其他属性,我对此并不着迷。
  3. 创建一个可以从控制器调用的单独服务,该控制器可以将函数列表填充到 ViewModel。这将涉及将多个服务注入到每个控制器中——这也不是很疯狂。

我倾向于#2。但我仍然觉得我忽略了更可靠的实现。有没有人处理过类似的事情?

【问题讨论】:

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


    【解决方案1】:

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

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

    @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 有责任知道如何以及在一个 ViewModel 中渲染什么不是 Editable 或另一个是 ReadOnly(不同的东西可以有不同的状态)。

    此外,由于我们正在讨论 DDD,我建议不要对 CRUD 操作建模。归根结底,DDD 是关于无处不在的语言,而“创建、更新、删除”并不是真正的语言业务。

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

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

    希望对你有帮助。

    【讨论】:

    • 明白了——这很有意义,并且完全符合我决定采用的方法。一旦我完成它,我将发布我的最终代码。另外,我已经将用户访问/验证作为业务规则处理,以及以操作过滤器属性的形式进行的一些角色检查,但该项目的要求之一是隐藏功能查看无法访问它们的用户。所以这纯粹是装饰性的。
    【解决方案2】:

    也许您需要使用 SimpleMembership 角色:

    Assigning Roles with MVC SimpleMembership

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

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

    在你看来例如:

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

    【讨论】:

    • 对于我要解决的问题,角色将无济于事,因为用户被分配了对特定对象的访问权限。管理员将对象分配给用户。但我需要一种方法来检查用户角色中的某人是否有权对给定对象执行特定功能。
    • 谢谢欧德莱。这个问题的答案看起来非常接近我已经拥有的,除了他们只是使用 Html 帮助器方法而不是直接调用静态方法。我认为这个解决方案会导致我试图避免的相同问题,即对数据库进行多次往返调用。我认为如果只是我试图在给定视图上控制的几个动作,这会很好,但我的应用程序会有几个。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-09
    • 2014-08-18
    • 2014-04-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多