ASP.NET MVC3 Role and Permission Management -> With Runtime Permission Assignment

China☆狼群 提交于 2019-11-27 07:00:43

What options are strategies are available to allow permissions on MVC Controllers/Views/Actions to be defined outside of attributes (as in a database) and evaluated and applied at runtime?

A custom Authorize attribute is one possibility to achieve this:

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

and then:

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

As I'm lazy I couldn't be bothered rolling my own attribute and used FluentSecurity for this. In addition to the ability to apply rules at run time it allows a custom way to check role membership. In my case I have a configuration file setting for each role, and then I implement something like the following;

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

the application roles are then applied like so

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

and then the check is performed by

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

You could of course pull roles from a database. The nice thing about this is that I can apply different rules during development, plus someone has already done the hard work for me!

You could also consider doing task/activity based security and dynamically assign permission to perform those tasks to different groups

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

You would need to mangle the provider a little bit to work with this but it is possible to stay inline with the .net authorisation

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

If you need to do Method or Controller based authorization (deny access to the whole method or controller) then you can override OnAuthorization in the controller base and do your ouwn authorization. You can then build a table to lookup what permissions are assigned to that controller/method and go from there.

You can also do a custom global filter, which is very similar.

Another option, using your second approach, is to say something like this:

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

And then in your controller populate MethodRoles with the roles assigned to that method.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!