【问题标题】:Dynamic Access Control with ASP.NET Identity使用 ASP.NET 标识的动态访问控制
【发布时间】:2016-04-26 20:52:46
【问题描述】:

也许我在 ASP.NET Identity (2.2.1) 的“文档”中的某个地方忽略了这一点,但我很难理解创建控制器和管理角色的接口的意义。我理解管理用户(CRUD + 分配角色)的意义,但就角色而言,CRUD 对我来说没有意义,除非有一种方法可以在运行时动态检测控制器的访问(IsInRole)。我有两个问题:

1] 当您必须首先在代码中配置应用程序以设置Authorize 属性以设置应具有的角色时,是否需要投入资源和时间来为角色创建 CRUD访问权限?

2] 有没有办法捕捉用户从控制器甚至控制器实例请求操作的时刻,以便在该点从数据库检查权限?

【问题讨论】:

  • 您可以在类(控制器)级别甚至方法级别(操作)上使用授权属性,因此用户可以请求控制器,但不能请求所有操作
  • 正确。这就是我所面临的难题。既然必须对角色进行硬编码,为什么还要开发一种方法来管理角色?

标签: c# asp.net asp.net-mvc asp.net-mvc-4 asp.net-identity


【解决方案1】:

我能在 SO 上找到的最佳答案是:

Dynamically add roles to authorize attribute for controller

这正是我想要完成的工作,这证明了我为角色创建 CRUD 的设计是合理的。此时,由于我可以使用上述方法将角色动态添加到控制器,因此我可以动态创建角色,然后将其包含在控制器的要求中以加强访问。

【讨论】:

    【解决方案2】:
    1. 我发现角色非常有用。我没有装饰每个控制器,而是将角色装饰放在为站点的每个部分定义的抽象类上。然后在一个部分中使用的每个控制器都继承自该部分的抽象类。

    2. 您可以使用 Http 模块并覆盖 AuthorizeRequest 事件。但我认为对每个请求进行数据库查询并不是一个好主意。角色存在于内存中,因此角色授权会非常高效。

    编辑:
    根据您的 cmets,您可以创建一个自定义属性来执行此操作。以下是我对如何完成的想法。在 OnAuthorization 事件中,我将为每个角色创建一个 if 块。如果用户是该角色的成员,请检查该角色是否有权访问当前控制器。该示例演示了仅针对一个名为 Admin 的角色的想法。

    using System.Web.Mvc;
    using System.Security.Claims;
    
    namespace MyApp.Filters
    {
        public class CustomAttribute : AuthorizeAttribute
        {
            private List<string> adminControllers;
    
            public CustomAttribute()
            {
                this.adminControllers = new List<string>();
    
                //This would be a DB call
                this.adminControllers.Add("MyApp.Controllers.AccountController");
                this.adminControllers.Add("MyApp.Controllers.AdministrationController");
            }
    
            public override void OnAuthorization(AuthorizationContext filterContext)
            {
                base.OnAuthorization(filterContext);
    
                //Get the roles for the current user
                var identity = (ClaimsIdentity)filterContext.HttpContext.User.Identity;
                var roles = identity.Claims.Where(c => c.Type == ClaimTypes.Role)
                            .Select(c => c.Value).ToList();
    
                //Check if current user has the Admin role
                if (roles.Contains("Admin"))
                {
                    //Check if Admin role has access to current controller
                    if (this.adminControllers.Contains(filterContext.Controller.ToString()))
                    {
                        filterContext.Result = new RedirectResult("~/Home/Error");
                    }
                }
    
    
            }
        }
    }
    

    【讨论】:

    • 感谢克林特的回复。所以就#2而言,没有办法有效地管理动态角色访问,对吗?如果我在数据库中的表中配置了权限(想想基于组或权限的访问),那么每次用户尝试操作或访问控制器时,我都必须点击数据库,对吗?
    • #1,正如您所回答的,您必须在抽象类或控制器上对每个角色进行硬编码。那么在应用程序中为角色创建 CRUD 的目的是什么?因此,为什么我对#2 如此好奇。企业应用程序中的安全性目的应该是允许管理员对特定用户或组或角色的应用程序的某些区域实施访问控制。如果我不知道存在哪些角色,如何在我的应用程序中实现它们?
    • @-Keith - 对你关于#2 的问题是肯定的。对于您对 #1 的回复,我只允许管理员访问角色 CRUD 页面。实际上,我在默认身份数据库中添加了一个 Profile 表,并为管理员提供了创建配置文件并将其分配给用户的能力。我的个人资料只是角色列表。我还做过一些网站,当用户注册时,他们会以编程方式分配默认角色。同样,角色 CRUD 页面仅适用于站点管理员。
    • 所以也许我以错误的方式问了我的问题。为用户分配角色非常好。我明白了,实际上我已经实现了。问题是定义这些角色可以动态访问的内容。我实际上曾考虑过创建一个 Menu 实体,并包含一个具有 Controller、Action 和 Roles(IdentityRole 列表)的 MenuItem 实体集合,如果用户处于该角色,他们将有权访问该菜单项。问题是在控制器级别而不是菜单项上定义安全性。这有意义吗?
    • 好吧,也许我读你的问题太快了。我有个主意。我会更新我的答案。
    猜你喜欢
    • 2014-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多