C# 视图和视图模型如何利用MVC 5中基于声明的授权?

C# 视图和视图模型如何利用MVC 5中基于声明的授权?,c#,asp.net-mvc-5,asp.net-identity,claims-based-identity,asp.net-authorization,C#,Asp.net Mvc 5,Asp.net Identity,Claims Based Identity,Asp.net Authorization,在我的项目中,我使用基于声明的授权和身份验证实现了ASP.NET Identity 2.x。 我添加了对索赔授权属性的支持 以下是我提出的允许/不允许员工使用积垢的主张 public class ResourceClaimTypes { public const string CreateEmployee = "urn:company:Employee:Create"; public const string ReadEmployee = "urn:company:Employe

在我的项目中,我使用基于声明的授权和身份验证实现了ASP.NET Identity 2.x。 我添加了对索赔授权属性的支持

以下是我提出的允许/不允许员工使用积垢的主张

public class ResourceClaimTypes
{
    public const string CreateEmployee = "urn:company:Employee:Create";
    public const string ReadEmployee = "urn:company:Employee:Read";
    public const string UpdateEmployee = "urn:company:Employee:Update";
    public const string DeleteEmployee = "urn:company:Employee:Delete";
}
操作如下所示:

    [ClaimsAuthorize( ResourceClaimTypes.ReadEmployee )]
    public ActionResult Index()
    {
        return View();
    }
我不太明白的是如何在视图及其视图模型中使用这些声明。 例如,有一个用于显示员工的视图,它是一个简单的网格。 然后是编辑和创建员工的视图

public class ResourceClaimTypes
{
    public const string CreateEmployee = "urn:company:Employee:Create";
    public const string ReadEmployee = "urn:company:Employee:Read";
    public const string UpdateEmployee = "urn:company:Employee:Update";
    public const string DeleteEmployee = "urn:company:Employee:Delete";
}
视图和视图模型现在应该能够根据用户的声明隐藏或显示保存/更新/删除按钮

视图上的方法:

索引->如果存在ReadEmployee索赔,则应显示所有员工,否则视图仍应可访问,但会显示一条消息“无需查看员工”

创建/编辑->用户仍应能够浏览这些视图,但“创建”/“保存”按钮不应可见

删除->所有“删除”按钮都应隐藏

底线是,视图应该是可访问的,但是创建/保存按钮应该是隐藏的。

如何做到这一点

*更新/我的解决方案*

我就是这样做的。 根据Derek的建议,我使用了基于操作/资源的身份验证。除了ASP.NET Identity,我还实现了IUserClaimStore接口,以从DB获取声明

视图和视图模型(!)不包含类似于CanRead、CanWrite的内容 我正在使用KendoUI,并为按钮创建了一个扩展方法

在扩展方法中,我可以访问自定义ResourceAuthorizationManager(请参阅Dominik Baier的博客)。因此,在创建按钮时,我可以调用HttpContaxtBase.CheckAccess(…)来确定按钮是否应该启用/可见

我唯一需要的是告诉扩展方法要检查访问的操作/资源组合

例如:

@Html.LinkButton(Action.Create, Resource.Employee)
这就是视图中显示(或不显示)一个显示“创建”并指向员工控制器的创建视图的按钮所需的全部内容。
非常干净,IMHO。

您可以访问项目中任何地方当前用户的声明,视图也不例外。只需将当前用户的身份强制转换为
claimsIdentity
,即可访问用户的声明:

var claims= ((ClaimsIdentity)HttpContext.Current.User.Identity).Claims;
您也可以为此编写扩展方法:

public static bool CanEdit(this IIdentity identity)
{  
     return identity.IsAuthenticated
        && identity is ClaimsIdentity
        && ((ClaimsIdentity)identity).HasClaim(x =>
            x.Type == "EditClaim" && x.Value == "true");
}
然后,您可以轻松编写以下代码:

if(HttpContext.Current.User.Identity.CanEdit())
{
    //your code
}

但是,即使你可以直接查看视图中的声明,考虑控制器中的检查请求,并通过视图模型向视图发送简单的真值或假值,以便更好地处理。

因为我们不想把逻辑和观点混为一谈。改为在控制器中检查权限要好得多。考虑这一点:

class PrivilegesViewModel
{
    public bool CanEdit{get;set;}
    public bool CanRead{get;set;}
    // and so on
}

class PostViewModel
{
    // our model data
    public PrivilegesViewModel Privileges{get;set;}
}
在控制器中:

public ActionResult Edit(int id)
{
    PostViewModel model=_postManager.Get(id);
    model.Privileges=new PrivilegesViewModel
    {
        CanEdit=HttpContext.Current.User.Identity.CanEdit(),
        // and so on
    }
    return View(model);
}
现在在您看来,只需检查布尔值

@if(model.Privileges.CanEdit)
{
    // print the button
}

你应该看看Thinktecture的Dominic Baier的一个产品

下面的文章将解释如何优雅地实现您的目标

他们有Git Hub回购的例子

**编辑**

下面是您需要遵循的GitHub示例的链接


实际上,您应该只从控制器设置模型的属性,并在视图中检查模型,而不是将视图调出给其他控制器code@TrevorPilley我并没有说要在视图中调用这个。我刚刚指出,声明可以在属性之外访问。当然,最好检查控制器中的声明,并将结果作为视图模型发送给视图。我指的是这一行“但即使您可以直接检查视图中的声明”@TrevorPilley实际上在这一行中,我试图温暖读者不要在视图中使用它,并鼓励读者在控制器中使用它。@SamFarajpourGhamari感谢您的回复。我已经在检查控制器动作的声明。我不确定我是否理解“检查控制器中的声明并通过视图模型发送简单的真值或假值”。这是什么意思?你能进一步解释一下吗?谢谢。是的,我读过很多多米尼克的帖子,但没有看到这篇。我正在使用ASP.NET Identity并自己实现ICLAIMStore,这是我添加存储在DB中的声明的地方。这是否仍然适用于上述基于行动/资源的方法?谢谢。我已经有一段时间没有研究过这个问题了,但我看不出有什么理由不起作用。试试看。对我来说,这是一个非常好的方法,你可以对你的资源进行单元测试。你在用饼干吗?是的,饼干。我在他们的示例中缺少的是我在原始问题中提出的问题:ViewModels和Views如何优雅地使用授权?我用控制器/动作获取零件,但我需要根据声明在视图中隐藏/显示按钮。再次感谢,你少了一个角色。在视图中,可以包装内容,例如CheckAccess()方法中的按钮。在GitHub上有一个完整的工作示例。例如,在项目列表中,您可以检查列表中每个项目的访问权限,我将查看是否可以找到它。现在我看到了。因此,我将从默认的ResAuthMan派生,并以某种方式注入索赔服务/回购,从而为给定用户提供索赔。然后我可以对此做出反应。我假设重新授权人将生活在基础设施层而不是web应用程序中?谢谢你,德里克。