Policy and Resource based authorization in ASP NET Core
Policy and Resource based authorization in ASP NET Core

Introduction

In this post, we will see how to implement Policy and Resource based authorization in ASPNETCore. There are instance where we need to validate the incoming data model. We will see how to validate the data model and authorize.

In our example, say we have two entities namely, Category and Product. Examples in this post shows how to validate the policy requirement along with the incoming model data which is inside the request body.

Are you looking for Azure AZ-203 certifications? Learn more by visiting below link.

 public class Product
    {
        public int Id { get; set; }
        [Required]
        [MinLength(5), MaxLength(200)]
        public string Name { get; set; }
        public decimal Price { get; set; }
        public DateTime? AvailableSince { get; set; }
        public int StockCount { get; set; }
        public int CategoryId { get; set; }
        public Category Category { get; set; }
        public List ProductImages { get; set; }
        public Status Status { get; set; }
    }

 public class Category
    {
        public int Id { get; set; }
        [Required]
        [MinLength(2), MaxLength(200)]
        public string Name { get; set; }
        public Status Status { get; set; }
    }

An authorization policy consists of one or more requirements. Policy is registered as part of the authorization service configuration, in the ConfigureServices method in the startup class.

Let us register two policy in our startup class as mentioned above.

 
services.AddAuthorization(options =>
            {
                options.AddPolicy("ProductAuthorizationPolicy", policy =>
                       policy.Requirements.Add(new ProductRequirement()));

                options.AddPolicy("CategoryAuthorizationPolicy", policy =>
                      policy.Requirements.Add(new CategoryRequirement()));

            });
Configure policy requirement in ConfigureService method

ProductRequirement and CategoryRequirement are the class which implements IAuthorizationRequirement. IAuthorizationRequirement is from the namespace Microsoft.AspNetCore.Authorization

Let's take a look at CategoryRequirement Resource based Authorization handler.

Policy and Resource based authorization in ASPNETCore

{
    public class CategoryAuthorizationHandler :
    AuthorizationHandler
    {
        protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
                                                       CategoryRequirement requirement,
                                                       Category resource)
        {
            if (context.User.Identity?.Name != null && resource.Name != null)
            {
                context.Succeed(requirement);
            }

            return Task.CompletedTask;
        }
    }

    public class CategoryRequirement : IAuthorizationRequirement { }
}

IAuthorizationService has two AuthorizeAsync method overloads: one accepting the resource and the policy name and the other accepting the resource and a list of requirements to evaluate.

Task AuthorizeAsync(ClaimsPrincipal user,
                          object resource,
                          IEnumerable requirements);
Task AuthorizeAsync(ClaimsPrincipal user,
                          object resource,
                          string policyName);
Policy based authorization in ASP NET Core

Now, how do we call this policy from an API endpoint and validate the requirement?

We have a controller for Category and that will look as shown below. The following code sample assume authentication has run and set the User property.

  [Route("api/[controller]")]
    [ApiController]
    public class CategoryController : ControllerBase
    {
        public CategoryController(IAuthorizationService authorizationService)
        {
            AuthorizationService = authorizationService;
        }

        public IAuthorizationService AuthorizationService { get; }

        // POST api/values
        [HttpPost]     
        public async Task Post([FromBody] Category category)
        {            
            /*
             This is a way the policy is manually triggered with the resource E.g. Category in this case
             */
            AuthorizationResult authResult = await AuthorizationService.AuthorizeAsync(User,
                category, "CategoryAuthorizationPolicy");

            if (!authResult.Succeeded)
            {
                return Forbid();
            }

            return Ok();
        }
    }
policy based authorization in ASPNETCore

If you wonder how to validate data model in a HTTPost call, here is an example.

In this below sample, we have an end point which accepts Product model in the request body

{
    public class ProductAuthorizationHandler : AuthorizationHandler
    {
        public ProductAuthorizationHandler(IHttpContextAccessor httpContextAccessor)
        {
            HttpContextAccessor = httpContextAccessor;
        }
        public IHttpContextAccessor HttpContextAccessor { get; }

        protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
                                                       ProductRequirement requirement)
        {
            Product productModel;
            using (var reader = new StreamReader(HttpContextAccessor.HttpContext.Request.Body))
            {
                var bodyContent = reader.ReadToEnd();
                productModel = JsonConvert.DeserializeObject(bodyContent);
            }

            if (context.User.Identity?.Name!=null && productModel!=null&& productModel.Price>3) 
            {
                context.Succeed(requirement);
            }

            return Task.CompletedTask;
        }
    }
    public class ProductRequirement : IAuthorizationRequirement { }
}
Policy and Resource based authorization in ASP NET Core

We have Product controller and code sample is below.

 [Route("api/[controller]")]
    [ApiController]
    public class ProductController : ControllerBase
    {    
        // POST api/values
        [HttpPost]
        [Authorize(Policy = "ProductAuthorizationPolicy")]
        public IActionResult Post([FromBody] Product product)
        {
            return Ok();
        }        
        
    }
Resource based authorization in ASPNETCore

This is just an example of how to validate the incoming data model which is in the request body.

In order to access the request body, we need IHttpContextAccessor to be injected by DI. With the instance of IHttpContextAccessor, the request body is read and converted to the string to the required model.

Do not forget to configure the IHttpContextAccessor in the ConfigureServices method in the startup class.


services.AddTransient<IHttpContextAccessor, HttpContextAccessor>();

If you would like to learn simple authorization, here is the link to it Simple Authorization.

Conclusion

In this post, we looked at how to implement Policy and Resource based authorization in ASPNETCore. Also, this post covered how to validate the incoming data model.

That’s all from this post. If you have any questions or just want to chat with me, feel free to leave a comment below.

Leave a Reply

Your email address will not be published. Required fields are marked *

Verified by MonsterInsights