C# ASP.NET MVC:基于用户';s访问

C# ASP.NET MVC:基于用户';s访问,c#,asp.net,asp.net-mvc,razor,domain-driven-design,C#,Asp.net,Asp.net Mvc,Razor,Domain Driven Design,在我的应用程序中,我有两个角色:管理员和用户。管理员可以分配用户,以允许他们对特定对象执行特定功能 由于这超出了SimpleMembership角色所能提供的范围,因此我有一个静态助手方法来检查用户是否有权访问特定函数: public static class SecurityCheck { public static bool UserHasAccess(int objectId, string functionName) { // Decorates the

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

由于这超出了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>
}
@foreach(Model.FooData中的变量项)
{
@DisplayFor(modelItem=>item.Name)
@DisplayFor(modelItem=>item.Notes)
@ActionLink(“查看数据”,“查看”,新的{@id=item.id})
@if(SecurityCheck.UserHasAccess(item.id,“编辑数据”))
{
@ActionLink(“编辑数据”,“编辑”,新的{@id=item.id})
}
@if(SecurityCheck.UserHasAccess(item.id,“Delete”))
{
@ActionLink(“Delete”,“Delete”,new{@id=item.id})
}
}
我必须相信有更好的方法可以做到这一点,因为对静态方法的每个单独调用都涉及到对数据库的单独往返,但我仍然坚持认为最好将代码放在哪里。我考虑过的一些想法:

  • 向my ViewModels添加方法以将函数列表传递到存储库,并返回用户可以为每个对象执行的函数列表。再进一步考虑,我甚至不确定这是否可能,因为它会很丑陋
  • 让ViewModel保持沉默,让我的应用层服务获取可用的函数。这将涉及向我的域模型对象添加额外的属性,我对此并不热衷
  • 创建一个单独的服务,该服务可以从控制器调用,该控制器可以将函数列表填充到ViewModel。这将涉及将多个服务注入到每个控制器中——这也不疯狂

  • 我倾向于#2,但我仍然觉得我忽略了一个更可靠的实现。以前有人处理过类似的问题吗?

    也许您需要使用SimpleMembership角色:

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

    Roles.AddUserToRole(model.UserName, "Admin");
    
    在您看来,例如:

    if (ViewContext.HttpContext.User.IsInRole("Admin"))
    
    我认为每个ViewModel“知道”可以用它做什么,不是吗?所以我们可以使隐式显式。ViewModel可以显式地具有CanEdit、CanDelete等属性

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

    @if (item.CanEdit)
    {
       @Html.ActionLink("Edit Data", "Edit", new {@id = item.Id})
    }
    
    您甚至可以使用一个助手,它将另一个
    布尔值
    作为参数来决定是否应该呈现(或启用)控件,但它是次要的:

    @Html.SecureActionLink(item.CanEdit, "Edit Data", "Edit", new {@id = item.Id})
    
    其想法是,用户界面的责任不是知道如何判断某些内容是否由于某些业务规则而被允许。 但用户界面有责任知道如何以及在一个视图模型中呈现什么,该视图模型不是可编辑的,或者另一个视图模型是只读的(不同的事物可能有不同的状态)

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

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

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


    希望有帮助。

    对于我试图解决的问题,角色将不会有帮助,因为用户被分配了对特定对象的访问权限。管理员将向用户分配对象。但我需要一种方法来检查用户角色中的人是否有权对给定对象执行特定功能。也许这会有帮助?谢谢Odrai。问题的答案是这个问题看起来与我已有的问题非常接近,只是他们只是使用了一个Html助手方法,而不是直接调用静态方法。我认为这个解决方案会导致与我试图避免的问题相同的问题,即对数据库进行多个往返调用。我认为如果我只执行了几个操作,这将很好正如试图控制给定视图一样,但我的应用程序将有几个。明白——这非常有意义,并且完全符合我决定采用的方法。我将在完成最终代码后发布它。另外,我已经将用户访问/验证作为一项业务规则处理,并在表单中进行一些角色检查操作过滤器属性,但该项目的一个要求是向无法访问这些功能的用户隐藏这些功能。