본문 바로가기
ASP.NET Core

ASP.NET Core] Custom Authorization Policy, Custom Authorization Requirement & Handler

by Fastlane 2022. 1. 17.
728x90
반응형

Custom Authorization Policy

다음과 같은 조건을 갖는 Policy를 만들어보자.

Member of the Admin role AND have Edit Role claim with a value of true
OR
Member of the Super Admin role 

 

다음의 Policy로는 내가 원하는 Policy를 만들 수 없다. 조건 사이에는 AND condition만 있다. 

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("EditRolePolicy", policy => policy
        .RequireRole("Admin")
        .RequireClaim("Edit Role", "true")
        .RequireRole("Super Admin")
    );
});

OR condition을 만들기 위해서는 RequireAssertion 함수를 사용한다. 

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("EditRolePolicy", policy => policy.RequireAssertion(context =>
        context.User.IsInRole("Admin") &&
        context.User.HasClaim(claim => claim.Type == "Edit Role" && claim.Value == "true") ||
        context.User.IsInRole("Super Admin")
    ));
});

 

Built-in asp.net core authorization requirements

  • RequireClaims()
  • RequireRole()
  • RequireAssertion()

위의 requirements는 IAuthorizationRequirement 인터페이스를 구현한다. custom authorization requirement를 만들 때도, 동일하게 인터페이스를 구현해야 한다. authorization handler안에 접근처리에 대한 로직을 구현한다. authorization handler는 AuthorizationHandler<T>를 상속받고, HandlerRequirementAsync() 함수를 구현한다. 

 

Custom Authorization Requirement & Handler

다음의 Requirement를 만들어보자. 

Admin user는 다른 Admin user의 role, claim은 수정할 수 있지만 자신은 수정할 수 없다. 

위의 요구사항을 처리하는 권한을 만들기 위해서는 query string parameter에 접근해야 한다. 따라서 built-in requirement는 사용할 수 없고, custom requirement & handler를 만들어야 한다. 

 

ManageAdminRolesAndClaimsRequirement.cs

using Microsoft.AspNetCore.Authorization;

namespace Employee.Security
{
    public class ManageAdminRolesAndClaimsRequirement : IAuthorizationRequirement
    {
    }
}

CanEditOnlyOtherAdminRolesAndClaimsHandler.cs

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.Filters;
using System.Security.Claims;

namespace Employee.Security
{
    public class CanEditOnlyOtherAdminRolesAndClaimsHandler : AuthorizationHandler<ManageAdminRolesAndClaimsRequirement>
    {
        protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, ManageAdminRolesAndClaimsRequirement requirement)
        {
            var authFilterContext = context.Resource as AuthorizationFilterContext;
            if (authFilterContext == null)
            { 
                return Task.CompletedTask;
            }

            string loggedInAdminid = context.User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier).Value;

            string adminIdBeingEdited = authFilterContext.HttpContext.Request.Query["userId"];

            if (context.User.IsInRole("Admin") &&
                context.User.HasClaim(claim => claim.Type == "Edit Role" && claim.Value == "true") &&
                adminIdBeingEdited.ToLower() != loggedInAdminid.ToLower())
            {
                context.Succeed(requirement);
            }
            
            return Task.CompletedTask;
        }
    }
}

SuperAdminHandler.cs

using Microsoft.AspNetCore.Authorization;

namespace Employee.Security
{
    public class SuperAdminHandler : AuthorizationHandler<ManageAdminRolesAndClaimsRequirement>
    {
        protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, ManageAdminRolesAndClaimsRequirement requirement)
        {
            if (context.User.IsInRole("Super Admin"))
            {
                context.Succeed(requirement);
            }
            return Task.CompletedTask;
        }
    }
}

Program.cs

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("EditRolePolicy",
        policy => policy.AddRequirements(new ManageAdminRolesAndClaimsRequirement()));
});


builder.Services.AddSingleton<IAuthorizationHandler, CanEditOnlyOtherAdminRolesAndClaimsHandler>();
builder.Services.AddSingleton<IAuthorizationHandler, SuperAdminHandler>();
728x90
반응형

댓글