{"id":1479,"date":"2025-06-26T13:20:13","date_gmt":"2025-06-26T13:20:13","guid":{"rendered":"https:\/\/www.cmarix.com\/qanda\/?p=1479"},"modified":"2026-02-05T12:05:45","modified_gmt":"2026-02-05T12:05:45","slug":"how-do-you-write-custom-authorization-policies-in-asp-net-core","status":"publish","type":"post","link":"https:\/\/www.cmarix.com\/qanda\/how-do-you-write-custom-authorization-policies-in-asp-net-core\/","title":{"rendered":"How do you Write Custom Authorization Policies in ASP.NET Core?"},"content":{"rendered":"\n<p>When building secure web applications with <a href=\"https:\/\/www.cmarix.com\/asp-net-core-development.html\">ASP.NET Core<\/a>, 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 &#8220;only authors can edit their own blog posts&#8221; you need custom authorization policies.<\/p>\n\n\n\n<p><strong>In this guide, you&#8217;ll learn:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>What are custom authorization policies<\/li>\n\n\n\n<li>How to define and register them<\/li>\n\n\n\n<li>How to apply them to controllers or actions<\/li>\n\n\n\n<li>A complete example: \u201cOnly the owner of a blog post can edit it\u201d<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">What is a Custom Authorization Policy?<\/h2>\n\n\n\n<p>An <strong>authorization policy<\/strong> consists of one or more <strong>requirements<\/strong>, and <strong>handlers<\/strong> that evaluate those requirements. You can create custom requirements to encapsulate business logic like checking ownership of a resource and handlers to enforce them.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Steps to Implement a Custom Authorization Policy<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Step 1: Create a Custom Requirement<\/h3>\n\n\n\n<p>A requirement is a class that implements the IAuthorizationRequirement interface.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>using Microsoft.AspNetCore.Authorization;\n\npublic class MustBePostOwnerRequirement : IAuthorizationRequirement\n{\n    \/\/ You can pass parameters like minimum age, roles, etc.\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Step 2: Create a Handler for the Requirement<\/h3>\n\n\n\n<p>Handlers contain the logic to determine if the user meets the requirement.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>using Microsoft.AspNetCore.Authorization;\nusing System.Security.Claims;\nusing System.Threading.Tasks;\n\npublic class MustBePostOwnerHandler : AuthorizationHandler&lt;MustBePostOwnerRequirement>\n{\n    private readonly IPostRepository _postRepository;\n\n    public MustBePostOwnerHandler(IPostRepository postRepository)\n    {\n        _postRepository = postRepository;\n    }\n\n    protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context,\n        MustBePostOwnerRequirement requirement)\n    {\n        if (context.Resource is HttpContext httpContext)\n        {\n            var routeData = httpContext.GetRouteData();\n            var postIdStr = routeData.Values&#91;\"id\"]?.ToString();\n\n            if (Guid.TryParse(postIdStr, out Guid postId))\n            {\n                var userId = context.User.FindFirst(ClaimTypes.NameIdentifier)?.Value;\n                var post = await _postRepository.GetPostByIdAsync(postId);\n\n                if (post != null &amp;&amp; post.AuthorId == userId)\n                {\n                    context.Succeed(requirement);\n                }\n            }\n        }\n    }\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Step 3: Register the Custom Policy in Startup.cs or Program.cs<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>services.AddAuthorization(options =>\n{\n    options.AddPolicy(\"MustBePostOwner\", policy =>\n    {\n        policy.Requirements.Add(new MustBePostOwnerRequirement());\n    });\n});\n\nservices.AddScoped&lt;IAuthorizationHandler, MustBePostOwnerHandler>();<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Step 4: Use the Policy in Controllers or Razor Pages<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;Authorize(Policy = \"MustBePostOwner\")]\npublic async Task&lt;IActionResult> Edit(Guid id)\n{\n    var post = await _postRepository.GetPostByIdAsync(id);\n    return View(post);\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Accessing HttpContext.RouteData<\/h3>\n\n\n\n<p>To access RouteData, make sure you&#8217;re using context.Resource properly. If you&#8217;re using Razor Pages or MVC controllers, this is typically HttpContext.<\/p>\n\n\n\n<p>You can also use a custom middleware or base controller if needed for cleaner architecture.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Summary<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Concept<\/strong><\/td><td><strong>Description<\/strong><\/td><\/tr><tr><td>IAuthorizationRequirement<\/td><td>Represents a requirement<\/td><\/tr><tr><td>AuthorizationHandler<\/td><td>Contains logic to check if a requirement is satisfied<\/td><\/tr><tr><td>AuthorizationPolicy<\/td><td>Groups one or more requirements<\/td><\/tr><tr><td>AuthorizeAttribute<\/td><td>Applies a policy to an action\/controller<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>Custom authorization policies in ASP.NET Core are ideal for enforcing business rules like resource ownership, access levels, or even subscription tiers.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Sample Use Cases for Custom Policies<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Only team leaders can remove users from a team.<\/li>\n\n\n\n<li>Only the account owner can edit billing details.<\/li>\n\n\n\n<li>Users must be verified before posting content<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>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 &#8220;only authors can edit their own blog posts&#8221; you need custom authorization policies. In this guide, you&#8217;ll [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":1481,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[4,3],"tags":[],"class_list":["post-1479","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dot-net","category-web"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/posts\/1479","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/comments?post=1479"}],"version-history":[{"count":7,"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/posts\/1479\/revisions"}],"predecessor-version":[{"id":1488,"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/posts\/1479\/revisions\/1488"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/media\/1481"}],"wp:attachment":[{"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/media?parent=1479"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/categories?post=1479"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/tags?post=1479"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}