ASP.NET MVC3角色和权限管理 - >使用运行时权限分配

时间:2011-09-02 16:19:16

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

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一起编译,因此我目前不知道在运行时中没有应用属性(允许其他权限)的机制,例如[Authorize(Roles =“Administrator,ContentEditor”)]。 / p>

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

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

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

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

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

4 个答案:

答案 0 :(得分:21)

  

有哪些选项可用于允许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();
}

答案 1 :(得分:16)

因为我很懒,所以我不能打扰我自己的属性并使用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();
}

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

答案 2 :(得分:2)

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

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

答案 3 :(得分:0)

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

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

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

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

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