Reputation: 645
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
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/
For your requirement , modify HandleRequirementAsync
function 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