【问题标题】:ASP.NET MVC3 Role and Permission Management -> With Runtime Permission AssignmentASP.NET MVC3 角色和权限管理 -> 使用运行时权限分配
【发布时间】:2011-11-09 07:49:01
【问题描述】:

ASP.NET MVC 允许用户在设计时为功能(即操作)分配权限,就像这样。

[Authorize(Roles = "Administrator,ContentEditor")]
public ActionResult Foo()
{
    return View();
}

要实际检查权限,可以在(Razor)视图中使用以下语句:

@if (User.IsInRole("ContentEditor"))
{
    <div>This will be visible only to users in the ContentEditor role.</div>
}

这种方法的问题是所有权限都必须在设计时设置并分配为属性。 (属性是与 DLL 一起编译的,所以我目前知道没有机制可以在 runtime 应用属性(以允许额外的权限),例如 [Authorize(Roles = "Administrator,ContentEditor")]。

在我们的用例中,客户端需要能够在部署后更改哪些用户拥有哪些权限

例如,客户端可能希望允许ContentEditor 角色中的用户编辑某些特定类型的内容。可能不允许用户编辑查找表值,但现在客户端希望允许此操作而不授予用户 all 下一个更高角色的权限。相反,客户端只是想修改用户的当前角色可用的权限。

有哪些策略可用于允许在属性之外(如在数据库中)定义 MVC 控制器/视图/操作权限并在运行时评估和应用? em>

如果可能,我们非常希望尽可能地坚持使用 ASP.NET 成员资格和角色提供程序功能,以便我们可以继续利用它提供的其他好处。

提前感谢您提供任何想法或见解。

【问题讨论】:

    标签: asp.net asp.net-mvc asp.net-mvc-3 asp.net-membership asp.net-roles


    【解决方案1】:

    有哪些策略可用于允许 MVC 上的权限 在属性之外定义的控制器/视图/动作(如在 数据库)并在运行时评估和应用?

    自定义 Authorize 属性是实现此目的的一种可能性:

    public class MyAuthorizeAttribute : AuthorizeAttribute
    {
        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            Roles = ... go ahead and fetch those roles dynamically from wherever they are stored
            return base.AuthorizeCore(httpContext);
        }
    }
    

    然后:

    [MyAuthorize]
    public ActionResult Foo()
    {
        return View();
    }
    

    【讨论】:

    • 我喜欢这种方法,因为它简单明了。今天下午我要测试一下。
    • 如果我在这里错了,请纠正我,但是每次引用自定义属性时查找角色不是效率低下吗?将角色分配给 User 对象一次以允许使用 User.IsInRole 不是更好吗,这在 Application_AuthenticateRequest 中应该是可能的: Context.User = new GenericPrincipal(Context.User.Identity, roles);
    • Ciaran Bruen 的问题在我看来像是对这个回复中的 Roles 语义的误解。它们不是用户的角色,它们是当前请求允许的角色。 go ahead and fetch those roles ... 部分应该从httpContext 中提取一些数据,然后执行一些逻辑来推断此httpContext 需要哪些角色。 (Msdn 在这个问题上也有点误导,但最后一行评论部分澄清了这一点。msdn.microsoft.com/en-us/library/…
    【解决方案2】:

    由于我很懒,我懒得滚动我自己的属性并为此使用FluentSecurity。除了在运行时应用规则的能力之外,它还允许以自定义方式检查角色成员资格。在我的情况下,我为每个角色设置了一个配置文件,然后我实现了类似以下的内容;

    // Map application roles to configuration settings
    private static readonly Dictionary<ApplicationRole, string> 
        RoleToConfigurationMapper = new Dictionary<ApplicationRole, string>
            {
                { ApplicationRole.ExceptionLogViewer, "ExceptionLogViewerGroups" }
            };
    

    然后像这样应用应用程序角色

    SecurityConfigurator.Configure(
        configuration =>
        {
            configuration.GetAuthenticationStatusFrom(() =>
                HttpContext.Current.User.Identity.IsAuthenticated);
            configuration.GetRolesFrom(() => 
                GetApplicationRolesForPrincipal(HttpContext.Current.User));
            configuration.ForAllControllers().DenyAnonymousAccess();
            configuration.For<Areas.Administration.Controllers.LogViewerController>()
                .RequireRole(ApplicationRole.ExceptionLogViewer);
        });
    
    filters.Add(new HandleSecurityAttribute());
    

    然后检查由

    public static object[] GetApplicationRolesForPrincipal(IPrincipal principal)
    {
        if (principal == null)
        {
            return new object[0];
        }
    
        List<object> roles = new List<object>();
        foreach (KeyValuePair<ApplicationRole, string> configurationMap in
                 RoleToConfigurationMapper)
        {
            string mappedRoles = (string)Properties.Settings.Default[configurationMap.Value];
    
            if (string.IsNullOrEmpty(mappedRoles))
            {
                continue;
            }
    
            string[] individualRoles = mappedRoles.Split(',');
            foreach (string indvidualRole in individualRoles)
            {
                if (!roles.Contains(configurationMap.Key) && principal.IsInRole(indvidualRole))
                {
                    roles.Add(configurationMap.Key);
                    if (!roles.Contains(ApplicationRole.AnyAdministrationFunction))
                    {
                        roles.Add(ApplicationRole.AnyAdministrationFunction);
                    }
                }
            }
        }
    
        return roles.ToArray();
    }
    

    您当然可以从数据库中提取角色。这样做的好处是我可以在开发过程中应用不同的规则,而且有人已经为我完成了艰苦的工作!

    【讨论】:

    • Blowdart,我也喜欢使用 Fluent 的想法,所以 Fluent Security 对我来说也很有趣。今晚我要看看这个,并将其与达林的解决方案进行比较。这两种都是具有不同优势的优秀方法。
    • 如果您在开始使用 Fluent Security 时需要任何帮助,请告诉我。我是 Twitter 上的 @kristofferahl,或者你可以在网站 (fluentsecurity.net) 上给我留言。
    • 谢谢。看起来 Fluent 是我现在可以真正使用的东西。
    【解决方案3】:

    您还可以考虑执行基于任务/活动的安全性,并动态地将执行这些任务的权限分配给不同的组

    http://lostechies.com/derickbailey/2011/05/24/dont-do-role-based-authorization-checks-do-activity-based-checks/

    您需要稍微修改提供程序才能使用此功能,但可以与 .net 授权保持一致

    http://www.lhotka.net/weblog/PermissionbasedAuthorizationVsRolebasedAuthorization.aspx

    【讨论】:

      【解决方案4】:

      如果您需要进行基于方法或控制器的授权(拒绝访问整个方法或控制器),那么您可以覆盖控制器库中的 OnAuthorization 并进行自己的授权。然后,您可以构建一个表来查找分配给该控制器/方法的权限并从那里开始。

      你也可以做一个自定义的全局过滤器,非常相似。

      使用第二种方法的另一种选择是这样说:

      @if (User.IsInRole(Model.MethodRoles)) 
      { 
          <div>This will be visible only to users in the ContentEditor role.</div> 
      } 
      

      然后在您的控制器中使用分配给该方法的角色填充 MethodRoles。

      【讨论】:

      • 神秘人,如果我重写 OnAuthorization 会有什么副作用?我想看看那里发生了什么。感谢您的信息。
      • @Anthony Gatlin - 我不确定你所说的副作用是什么意思。它只是作为管道的一部分的扩展点。您可以做出任何您想要的授权决定,然后继续处理。
      猜你喜欢
      • 2012-10-25
      • 2016-11-28
      • 2017-10-16
      • 2012-10-16
      • 2023-01-02
      • 2010-12-23
      • 2015-06-24
      • 1970-01-01
      • 2015-09-14
      相关资源
      最近更新 更多