6
votes

I am working on asp.net mvc 5. I want to assign permissions of controllers' action methods to roles dynamically without hard conding the roles in Authorize attribute.

Here is the scenario - In my project, I have four roles - Student, Teacher, Program Officer and Admin. I want that admin can change the accessability of each role whenever he wishes. I do not want to hard code the authorize attribute with role names before every action name of controller because admin will not then be able to change the permissions of each role.

I want to create a page where every action method of controller will be listed as checkbox and admin can select action checkboxes for a role. Then that role users will get accessability of those action methods.

Here I want to make the UI as following -

Role Management UI

Can anyone please help me to do this by giving any suggestion or code or link?

3
Do you already use Roles in your project?SᴇM
Here I retrieved the role from the AspNetRole table. I seed this table with four roles. But my concern is how I can allow admin to assign permissions of action methods to a role from the UI. This UI is for demo purpose. I want to create like this.Jobayer Ahmmed
I've asked that question to know whether you use the part of assigning roles or no, so if yes, you just need to use that part, when you checking/unchecking your checkboxes.SᴇM
I have not assigned roles to the controller methods yet.Jobayer Ahmmed
hi I am looking for this solution too, it would be nice to map to the menu as wellTransformer

3 Answers

6
votes

Imagine you have service which returns array of roles based on controller and action name like this:

public class RoleProvider
{
    public string[] Get(string controller, string action)
    {
        // get your roles based on the controller and the action name 
        // wherever you want such as db
        // I hardcoded for the sake of simplicity 
        return new string[]{"Student", "Teacher"};
    }
}

Now you can write your own authorization attribute something like this:

public class DynamicRoleAuthorizeAttribute: AuthorizeAttribute
{
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        var controller = httpContext.Request.RequestContext
            .RouteData.GetRequiredString("controller");
        var action = httpContext.Request.RequestContext
            .RouteData.GetRequiredString("action");
        // feed the roles here
        Roles = string.Join("," ,_rolesProvider.Get(controller, action));
        return base.AuthorizeCore(httpContext);
    }
}

Now use your custom authorization attribute instead of older one like this:

[DynamicRoleAuthorize]
public ActionResult MyAction()
{

}
1
votes

I think the only way is to implement your own Authorize Attribute where you can implement your own logic for authorization.

And in your case you should have a table where associate roles and controllers action and check this table in your custom Authorize Attribute.

1
votes

While this does not give you the dynamics web page assignment you're looking for, If you are flexible in your approach... you can set up an Enum list of Roles Admin, Editor editor etc, and pass them as a parameter object (ENUM) as a param, so that the DynamicRoleAuthorize can use it load the roles that are allowed

from vivians blog The constructor accepts parameters of type object, that is the little trick. If you use parameters of type Enum, you will get the same error message as above. We can do that because an Enum is an object. To ensure that we are passing parameters of type Enum, we check the type of every roles. If one role is not of type Enum, the constructor will throw an ArgumentException. Then we set the standard Roles property with the name of our roles with the string.Join method.

using System;
using System.Linq;
using System.Web.Mvc;

namespace MvcApplication.HowTo.Attributes
{
     [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
public class AuthorizeEnumAttribute : AuthorizeAttribute
{
    public AuthorizeEnumAttribute(params object[] roles)
    {
        if (roles.Any(r => r.GetType().BaseType != typeof(Enum)))
            throw new ArgumentException("roles");

        this.Roles = string.Join(",", roles.Select(r => Enum.GetName(r.GetType(), r)));
    }
   }
}