Dynamic authorization of roles asp.net core

Sujit.Warrier picture Sujit.Warrier · Jun 28, 2017 · Viewed 13.3k times · Source

This is not a duplicate question or rather the solutions given in other solutions have not worked.

Lets say there is a controller

[Authorize(Roles=//set dynamically)]
public IActionResult DashBoard(LoginModel model)
{
}

I have tried the solutions in the following questions

  1. Add roles to authorize attribute

  2. dynamically assign controller action permissions to roles

  3. dynamically add roles to authorize attribute for controller (Error: Handle method - no suitable method found to override )

  4. can policy based authorization be more dynamic

All of these solutions do not work as either the methods overridden in the interfaces are not present (eg. authorizeAttribute does not contain a definition for AuthorizeCore) or in some cases IServiceCollection services does not contain a particular method

Answer

Tseng picture Tseng · Jun 28, 2017

You can't do that. [Authorize(Roles=//set dynamically)] must be know at compile time. Also using roles for this very reason is discouraged as pointed in blowdart's linked post from comments.

Instead, you should use claims and policies. Claims are fine grained permissions, for example "CreateCustomer" or "DeleteCustomer" or "ViewDashboard".

So you have to use it like

[Authorize(Policy = "ViewDashboard")]

These policies need to be know at compile time.

public class ViewDashboardRequirement : AuthorizationHandler<ViewDashboardRequirement>, IAuthorizationRequirement
{
    public override void Handle(AuthorizationContext context, ViewDashboardRequirement requirement)
    {
        if (context.User.HasClaim(c => c.Type == "dashboard:read"))
        {
            context.context.Succeed(requirement);
            return;
        }

        // only call fail if you do not want that other AuthorizationHandler may succeed with 
        // a different requirement
        // context.Fail();
    }
}

For an example on how to generate a generic handler (instead of writing a new Handler for each policy) see my answer here.

This will allow you to create configurable roles. Now you can create roles which consists as a bag of claims. Each claim may be one policies. When the user logs in, you add the claims that belong to a role to the list of users claims.

i.e.

  • Support: ViewDashboard, ViewCustomers, ViewContacts, ManageCases (support tickets)
  • Manager: ViewDashboard, ManageCustomers (View, Edit, Delete), ManageContacts (View, Edit, Delete)
  • Administrator: ManageDashboard (View, Edit)

etc.

Update from Comments.

You should be able to utilize ASP.NET Core Identity's claim and roleclaim abilities w/o changing a line of code, therefor you have the IdentityRole and IdentityRoleClaim classes. At runtime, you add a new IdentityRole (i.e. "Manager") and then add multiple IdentityRoleClaim (one for each permission/policy)