Search code examples
c#asp.netasp.net-mvcasp.net-identityauthorize-attribute

Dynamically add roles to authorize attribute for controller


I need to enable my admin user to change access permissions for users on the fly, such that they can create new Roles and add permissions to those Roles.

I want to be able to create an Authorize attribute to stick above my controller class that I can add roles to from a database, so that I don't have to 'set' the roles during development, as in [Authorize(Roles="Role1, Role2")] etc.

So something like [Authorize(Roles = GetListOfRoles()]

I found this question - ASP.NET MVC Authorize user with many roles which does something similar but maybe there's a way to change this such that it gets a list of permissions/roles from the db?


Solution

  • This is how I pulled off an attribute that could authorize users per method based on the permissions of the role of that user. I hope this helps somebody else:

    /// <summary>
    /// Custom authorization attribute for setting per-method accessibility 
    /// </summary>
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
    public class SetPermissionsAttribute : AuthorizeAttribute
    {
        /// <summary>
        /// The name of each action that must be permissible for this method, separated by a comma.
        /// </summary>
        public string Permissions { get; set; }
    
        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            SalesDBContext db = new SalesDBContext();
            UserManager<ApplicationUser> userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
            ApplicationDbContext dbu = new ApplicationDbContext();
    
            bool isUserAuthorized = base.AuthorizeCore(httpContext);
    
            string[] permissions = Permissions.Split(',').ToArray();
    
            IEnumerable<string> perms = permissions.Intersect(db.Permissions.Select(p => p.ActionName));
            List<IdentityRole> roles = new List<IdentityRole>();
    
            if (perms.Count() > 0)
            {
                foreach (var item in perms)
                {
                    var currentUserId = httpContext.User.Identity.GetUserId();
                    var relatedPermisssionRole = dbu.Roles.Find(db.Permissions.Single(p => p.ActionName == item).RoleId).Name;
                    if (userManager.IsInRole(currentUserId, relatedPermisssionRole))
                    {
                        return true;
                    }
                }
            }
            return false;
        }
    }