When building secure web applications with ASP.NET Core, you often need to control what users can or cannot access. The built-in [Authorize] attribute works well with simple role or claim checks, but for more advanced scenarios such as “only authors can edit their own blog posts” you need custom authorization policies.

In this guide, you’ll learn:

  • What are custom authorization policies
  • How to define and register them
  • How to apply them to controllers or actions
  • A complete example: “Only the owner of a blog post can edit it”

What is a Custom Authorization Policy?

An authorization policy consists of one or more requirements, and handlers that evaluate those requirements. You can create custom requirements to encapsulate business logic like checking ownership of a resource and handlers to enforce them.

Steps to Implement a Custom Authorization Policy

Step 1: Create a Custom Requirement

A requirement is a class that implements the IAuthorizationRequirement interface.

using Microsoft.AspNetCore.Authorization;
public class MustBePostOwnerRequirement : IAuthorizationRequirement
{ // You can pass parameters like minimum age, roles, etc.
}

Step 2: Create a Handler for the Requirement

Handlers contain the logic to determine if the user meets the requirement.

using Microsoft.AspNetCore.Authorization;
using System.Security.Claims;
using System.Threading.Tasks;
public class MustBePostOwnerHandler : AuthorizationHandler<MustBePostOwnerRequirement>{ private readonly IPostRepository _postRepository; public MustBePostOwnerHandler(IPostRepository postRepository) { _postRepository = postRepository; } protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, MustBePostOwnerRequirement requirement) { if (context.Resource is HttpContext httpContext) { var routeData = httpContext.GetRouteData(); var postIdStr = routeData.Values["id"]?.ToString(); if (Guid.TryParse(postIdStr, out Guid postId)) { var userId = context.User.FindFirst(ClaimTypes.NameIdentifier)?.Value; var post = await _postRepository.GetPostByIdAsync(postId); if (post != null && post.AuthorId == userId) { context.Succeed(requirement); } } } }
}

Step 3: Register the Custom Policy in Startup.cs or Program.cs

services.AddAuthorization(options =>{ options.AddPolicy("MustBePostOwner", policy => { policy.Requirements.Add(new MustBePostOwnerRequirement()); });
});
services.AddScoped<IAuthorizationHandler, MustBePostOwnerHandler>();

Step 4: Use the Policy in Controllers or Razor Pages

[Authorize(Policy = "MustBePostOwner")]
public async Task<IActionResult> Edit(Guid id)
{ var post = await _postRepository.GetPostByIdAsync(id); return View(post);
}

Accessing HttpContext.RouteData

To access RouteData, make sure you’re using context.Resource properly. If you’re using Razor Pages or MVC controllers, this is typically HttpContext.

You can also use a custom middleware or base controller if needed for cleaner architecture.

Summary

ConceptDescription
IAuthorizationRequirementRepresents a requirement
AuthorizationHandlerContains logic to check if a requirement is satisfied
AuthorizationPolicyGroups one or more requirements
AuthorizeAttributeApplies a policy to an action/controller

Custom authorization policies in ASP.NET Core are ideal for enforcing business rules like resource ownership, access levels, or even subscription tiers.

Sample Use Cases for Custom Policies

  • Only team leaders can remove users from a team.
  • Only the account owner can edit billing details.
  • Users must be verified before posting content