I am trying to implement a custom authorization requirement following a tutorial. It seems like
context.Resource
no longer contains AuthorizationFilterCo
public class CanEditOnlyOtherAdminRolesAndClaimsHandler :
AuthorizationHandler
{
private readonly IHttpContextAccessor httpContextAccessor;
public CanEditOnlyOtherAdminRolesAndClaimsHandler(IHttpContextAccessor httpContextAccessor)
{
this.httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor));
}
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
ManageAdminRolesAndClaimsRequirement requirement)
{
if (context.User == null || !context.User.Identity.IsAuthenticated)
{
context.Fail();
return Task.CompletedTask;
}
string loggedInAdminId =
context.User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier).Value;
string adminIdBeingEdited = httpContextAccessor.HttpContext.Request.Query["userId"].ToString();
if (context.User.IsInRole("Admin") &&
context.User.HasClaim(claim => claim.Type == "Edit Role" && claim.Value == "true") &&
adminIdBeingEdited.ToLower() != loggedInUserId.ToLower())
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
}
Then add the following services to ConfigureServices
method in Startup
class:
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthorization(options =>
{
options.AddPolicy("ManageRolesPolicy", policy => policy.Requirements.Add(new ManageAdminRolesAndClaimsRequirement()));
}
services.AddScoped();
}
If you want to handle a multiple custom authorization for a requirement:
in CanEditOnlyOtherAdminRolesAndClaimsHandler
class you check if the user is in Admin
role and has Edit Role
claim. Let's suppose that you require that the user must to be in Super Admin
role, in this scenario, you can either:
- edit the condition in CanEditOnlyOtherAdminRolesAndClaimsHandler
class to be as a following:
if (context.User.IsInRole("Admin") &&
context.User.HasClaim(claim => claim.Type == "Edit Role" && claim.Value == "true") &&
adminIdBeingEdited.ToLower() != loggedInUserId.ToLower() ||
context.User.IsInRole("Super Admin") && adminIdBeingEdited.ToLower() != loggedInUserId.ToLower())
{
context.Succeed(requirement);
}
- or customize another authorization handler for the new requirement which in this case is Super Admin
role:
Create a new class and name it ManageRolesAndClaimsSuperAdminHandler
, the implementation of this class should be as follows
public class ManageRolesAndClaimsSuperAdminHandler : AuthorizationHandler
{
private readonly IHttpContextAccessor httpContextAccessor;
public ManageUsersRolesSuperAdminHandler(IHttpContextAccessor httpContextAccessor)
{
this.httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor));
}
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, ManageAdminRolesAndClaimsRequirement requirement)
{
if (context.User == null || !context.User.Identity.IsAuthenticated)
{
context.Fail();
return Task.CompletedTask;
}
string loggedInAdminId = context.User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier).Value;
string adminIdBeingEdited = httpContextAccessor.HttpContext.Request.Query["userId"].ToString();
if (context.User.IsInRole("Super Admin") && adminIdBeingEdited.ToLower() != loggedInUserId.ToLower())
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
Now register the new handler in ConfigureServices
method in Startup
class
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthorization(options =>
{
options.AddPolicy("ManageRolesPolicy", policy => policy.Requirements.Add(new ManageAdminRolesAndClaimsRequirement()));
}
services.AddScoped();
services.AddScoped();
}