0

In asp.net core mvc project , I want to crate new user roles and give permission to each role for controller actions .
Let say , I have a SchoolController , inside this , I have three methods ,

  • CreateSchool
  • UpdateSchool
  • DeleteSchool

And Let's say I have Admin and Staff roles. I want to give access all methods to Admin and give UpdateSchool to Staff .
Meaning is, Admin can Create,Update,Delete School . And Staff can only UpdateSchool .
I will save this roles permission inside database like

Role
----------------------------------------
RoleId  Name
1       Admin
2       Staff


Module
----------------------------------------
ModuleId   Name
1          SchoolController/CreateSchool
2          SchoolController/UpdateSchool
3          SchoolController/DeleteSchool

RoleModules (middle table for relation of roles and module )
----------------------------------------
RoleId      ModuleId
1           1
1           2
1           3
2           2

Ok , let say we have 3 persons here , Person_1, Person_2 and Person_3 .
And they have different roles like

Person_1 ( Admin )
Person_2 ( Staff )
Person_3 ( Staff )

When users access to CreateSchool Controller's action , I want to check if current user has access to this action or not .

[Authorize]
public async Task<IActionResult> CreateSchool(SchoolViewModel model)
{
     //code to create school
}

For this , should I need to use IAuthorizationHandler's HandleRequirementAsync ?
Where should I retrieve from database and check for user's request ?
Is there any reference that meet with my requirement ??

Note : Roles and Modules will dynamically create in run-time .

Update : Should I use ActionFilter ? ( reference )

1 Answer 1

1

You may do this by using requirement and handler.

Create requirement class:

public class HasRoleRequirement: IAuthorizationRequirement { }

Then implement a handler:

public class RoleRequirementHandler : AuthorizationHandler<HasRoleRequirement>
{
    protected IHttpContextAccessor m_httpContextAccessor;

    public RequirementHandlerBase(IHttpContextAccessor httpContextAccessor)
    {
        m_httpContextAccessor = httpContextAccessor;
    }

    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, HasRoleRequirement requirement)
    {
        var requestPath = m_httpContextAccessor.Request.Path;
        var module = GetModule(path); // Get your module from DB
        var requiredRoles = GetRequiredRoles(module.ModuleId); // Get the required roles for the module/path
        bool isAuthorized = IsInAnyRole(m_httpContext.User, requiredRoles); // Check whether the user has any of the required roles
        if (isAuthorized)
        {
            context.Succeed(requirement);
        }
        else
        {
            context.Fail();
        }

        return Task.CompletedTask;
    }
}

Register the policy in the ConfigureServices method in Startup.cs:

services.AddAuthorization(options => 
{
    options.AddPolicy("HasRole", policy => policy.Requirements.Add(new HasRoleRequirement()));
}
services.AddSingleton<IAuthorizationHandler, RoleRequirementHandler>();

Use the authorization by decoration your method [Authorize(Policy = "IsInRole")]

For reusability and cleaner code, you may declare the policy name strings as constants in a static class.

See docs.

You will have to implement the methods GetModule. GetRequiredRoles and IsInAnyRole yourself.

Sign up to request clarification or add additional context in comments.

2 Comments

it's nice using HandleAsync method here , but as I mentioned in question , (Admin and Staff ) roles are just for sample and those will be dynamically created in run-time . And other roles too . So , I cannot use the attribute [Authorize(Policy = "IsAdmin")] . any suggestion ?
You can inject IHttpContextAccessor into your requirement handler and use it to get the current request. Then, map the action to your roles and check if the user has the roles required. Use only one requirement, HasRoleRequirement, maybe.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.