【问题标题】:How can Views and ViewModels utilize claims-based authorization in MVC 5?Views 和 ViewModels 如何在 MVC 5 中利用基于声明的授权?
【发布时间】:2015-11-22 23:29:57
【问题描述】:

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

这是我提出的允许/禁止对员工进行 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();
    }

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

视图和视图模型现在应该能够根据用户声明隐藏或显示保存/更新/删除按钮。

观点方法:

Index -> 如果存在 ReadEmployee 声明,则应该显示所有员工,否则视图应该仍然可以访问,但会显示“无查看员工的权限”消息。

创建/编辑 -> 用户应该仍然能够导航到这些视图,但“创建”/“保存”按钮应该不可见。

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

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

如何做到这一点?

* 更新/我的解决方案 *

这就是我最终做到的方式。 按照 Derek 的建议,我使用了基于操作/资源的身份验证。除了 ASP.NET Identity,我还实现了 IUserClaimStore 接口以从数据库中获取声明。

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

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

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

剃刀示例:

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

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

【问题讨论】:

    标签: c# asp.net-mvc-5 asp.net-identity claims-based-identity asp.net-authorization


    【解决方案1】:

    您应该看看 Thinktecture 的 Dominic Baier 的产品,以了解类似的情况。

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

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

    他们在 Git Hub 存储库中有示例。

    ** 编辑 **

    这是您需要关注的 GitHub 示例的链接。

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

    【讨论】:

    • 是的,我已经阅读了许多 Dominik 的帖子,但还没有看到这一篇。我正在使用 ASP.NET Identity 并自己实现 IClaimsStore,这是我添加存储在数据库中的声明的地方。这仍然适用于上述基于操作/资源的方法吗?谢谢。
    • 我已经有一段时间没有研究这个了,但我看不出它为什么不起作用。试一试。它对我来说是一个很好的方法,你可以对你的资源进行单元测试。您在使用 Cookie 吗?
    • 是的,cookies。我在他们的示例中缺少的是我在最初的问题中提出的问题:ViewModels 和 Views 如何优雅地使用授权?我得到了控制器/动作的部分,但我需要根据声明在视图中隐藏/显示按钮。再次感谢。
    • 您遗漏了一部分。在视图中,您可以包装内容,例如 CheckAccess() 方法中的按钮。 GitHub 上有一个完整的工作示例。例如,项目列表,您可以检查列表中每个项目的访问权限,我会看看是否可以找到它。并发布链接。
    • 现在我明白了。所以我会从默认的 ResAuthMan 派生,并以某种方式注入一个声明服务/存储库,它会给我一个给定用户的声明。然后我可以对此做出反应。我假设 ResAuthMan 将存在于基础设施层而不是 Web 应用程序中?谢谢德里克。
    【解决方案2】:

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

    【讨论】:

    • 你真的应该从控制器中设置模型的属性并在视图中检查模型,而不是让视图调用其他代码
    • @TrevorPilley 我没有说在视图中调用它。我只是指出声明可以在属性之外访问。当然,最好在控制器中检查声明并将结果作为视图模型发送给查看。
    • 我指的是这一行“但即使您也可以直接在视图中检查声明”
    • @TrevorPilley 实际上在这一行中我试图温暖读者不要在视图中使用它,并鼓励读者改为在控制器中使用。
    • @SamFarajpourGhamari 感谢您的回复。我已经在检查控制器操作的声明。我不确定我是否理解“检查控制器中的声明并通过视图模型发送简单的真值或假值”。那是什么意思?你能进一步解释一下吗?谢谢。
    猜你喜欢
    • 1970-01-01
    • 2014-02-20
    • 2014-03-15
    • 1970-01-01
    • 2021-04-13
    • 2011-08-25
    • 2012-11-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多