arjun
arjun

Reputation: 645

Complex role authorization Asp.net core MVC

I have written following code to handle authorization. Providing access or no access can be achieve with authorize attribute. My question is : Is there a standard way of handling partial access where some users have access to everything and some other to few resources based on role as shown in the if statement below? Writing if else block such as shown below everywhere doesn't seem right to me? Please suggest if there are any better way of doing it.

 [Authorize(Roles ="admin,superadmin")]
   public async Task<IActionResult> Index()
   {
           if (User.IsInRole("superadmin"))
            {
                //get all groups
            }
            else
            {
              //get only groups that the user belong to
            }

   }

Updated (solution) based on this discussion: I have added following code to handle my scenario. Any comments or suggestions welcome.

public class SuperAdminUsersRequirement : IAuthorizationRequirement
    {
        public SuperAdminUsersRequirement(params string[] roles)
        {
            AllowedRoles = roles;
        }
        public string[] AllowedRoles { get; set; }
    }
    public class SuperAdminAuthorizationHander : AuthorizationHandler<SuperAdminUsersRequirement>
    {
        protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, SuperAdminUsersRequirement requirement)
        {
            if(UserIsAllowed(context, requirement))
            {
                context.Succeed(requirement);
            }
            else
            {
                context.Fail();
            }
            return Task.CompletedTask;
        }

        private bool  UserIsAllowed(AuthorizationHandlerContext context, SuperAdminUsersRequirement requirement)
        {
            if (context.User.Claims != null)
            {
                var claims = from userClaims in context.User.Claims
                             where userClaims.Type == ClaimTypes.Role
                             select userClaims.Value;
                if (requirement.AllowedRoles.Intersect(claims, StringComparer.OrdinalIgnoreCase).Any())
                {
                    return true;
                }
                else
                {
                    return false;
                }

            }
            else
            {
                return false;
            }
        }
    }

startup.cs : can be configure to add more role having all access

services.AddAuthorization(options =>
            {
                options.AddPolicy("HasAllAccess", policy =>
                    policy.Requirements.Add(new SuperAdminUsersRequirement(AdminRole.SUPER_ADMIN.ToString()
                        )));
            });

controller.cs

var authorizationResult = await _authorizationService.AuthorizeAsync(User, "HasAllAccess");

 if(authorizationResult.Succeeded)
            {
 //fetch everything
    }
else
{
  // fetch partial data
}

Upvotes: 1

Views: 383

Answers (1)

Nan Yu
Nan Yu

Reputation: 27588

There are a lot of code samples available for Resource-based authorization in ASP.NET Core :

https://andrewlock.net/resource-specific-authorisation-in-asp-net-core/

https://github.com/MicrosoftDocs/architecture-center/blob/master/docs/multitenant-identity/authorize.md

For your requirement , modify HandleRequirementAsyncfunction in AuthorizationHandler which inheriting from AuthorizationHandler<YourRequirement, ResourceName>, you should check whether user has correct role/roles based on your requirement :

if (context.User.HasClaim(ClaimTypes.Role, Roles.SurveyAdmin))
{
    context.Succeed(requirement);
    return Task.FromResult(0);
}

Or :

if (context.User.IsInRole("super_user"))
{
    context.Succeed(requirement);
    return Task.FromResult(0);
}

Upvotes: 1

Related Questions