Views 和 ViewModels 如何在 MVC 5 中使用基于声明的授权?

How can Views and ViewModels utilize claims-based authorization in MVC 5?

在我的项目中,我已经实现了 ASP.NET 身份 2.x 以及基于声明的授权和身份验证。 我添加了对声明授权属性 as described here.

的支持

以下是我提出的会 allow/disallow 对员工进行 CRUD 的声明。

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();
    }

我不太明白的是如何在 视图及其视图模型 中使用这些声明。 例如,有一个用于显示员工的视图,它是一个简单的网格。 然后是 编辑创建 员工的视图。

视图和视图模型现在应该能够根据用户的要求隐藏或显示 Save/Update/Delete 按钮。

处理意见:

如果存在 ReadEmployee 声明,

Index -> 应显示所有员工,否则视图仍应可访问,但会显示一条消息 "No premission to view employees".

Create/Edit -> 用户应该仍然可以导航到这些视图,但是 "Create"/"Save" 按钮不应该可见。

删除 -> 应隐藏所有 "Delete" 按钮。

底线是,视图应该可以访问,但是 Create/Save 按钮应该 隐藏。

如何做到?

* 更新/我的解决方案 *

我就是这样完成的。 根据 Derek 的建议,我使用了基于 Action/Resource 的身份验证。除了 ASP.NET Identity,我还实现了 IUserClaimStore 接口以从数据库中获取声明。

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

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

我唯一需要的是告诉扩展方法要检查访问权限的 action/resource 组合。

剃刀示例:

@Html.LinkButton(Action.Create, Resource.Employee)

这就是视图中显示(或不显示)显示 "Create" 并指向 Employee 控制器的 Create 视图的按钮所需的全部内容。 非常干净,恕我直言。

您可以在项目的任何位置访问当前用户的声明,视图也不例外。只需将当前用户的身份转换为 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
}

但即使您可以直接检查视图中的声明,也可以考虑检查控制器中的声明,并通过视图模型将简单的 true 或 false 值发送到您的视图以获得更好的方法。

因为我们不想将我们的逻辑混入视图中。最好在控制器中检查权限。考虑一下:

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);
}

现在在您的视图中只需检查 bool 值;

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

你应该看看 Thinktecture 的 Dominic Baier 的产品,这样的东西。

下面的文章将解释如何优雅地实现您想要的东西。

http://leastprivilege.com/2014/06/24/resourceaction-based-authorization-for-owin-and-mvc-and-web-api/

他们那里有示例 Git Hub 仓库。

** 编辑 **

这是您需要遵循的 link 到 GitHub 示例。

https://github.com/IdentityModel/Thinktecture.IdentityModel/tree/master/samples/OWIN/ResourceAuthorization/Chinook