An authorization policy is a named set of access-control requirements that determines whether an authenticated principal may perform an action. Apply different policies to read and write operations when authentication alone is too broad. section 9.6 section 9.7
Build policies from three cooperating parts:
- Register a named policy with AddAuthorization, require an authenticated user, and select the JWT bearer authentication scheme. section 9.6
- Attach the policy by name to controller actions with Authorize, allowing read actions and restricting mutations independently. section 9.6
- Represent specialized access rules as requirements and evaluate them in authorization handlers. section 9.6 section 9.7
Authenticated reads, restricted writes
Apply an AuthenticatedUsers policy to GET actions and an OnlyMe policy to create, update, and delete actions. OnlyMe succeeds when the authenticated principal has a preferred_username claim matching the configured developer identity. section 9.6
Listing 9.20 Controller action-level authorization
[ApiController]
[Route("[controller]")]
public class CatalogController : ControllerBase #1
{
[HttpGet]
[Authorize("AuthenticatedUsers")] #2
public IAsyncEnumerable<Book> GetBooks(
string? titleFilter = null)
{ /*...*/ }
[HttpGet("{id}")]
[Authorize("AuthenticatedUsers")] #2
public Task<Book?> GetBook(int id)
{ /*...*/ }
[HttpPost]
[Authorize("OnlyMe")] #3
public async Task<Book> CreateBook(
BookCreateCommand command)
{ /*...*/ }
[HttpPatch("{id}")]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[Authorize("OnlyMe")] #3
public async Task<IActionResult> UpdateBook(
int id, BookUpdateCommand command)
{ /*...*/ }
[HttpDelete("{id}")]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[Authorize("OnlyMe")] #3
public async Task<IActionResult> DeleteBook(int id)
{ /*...*/ }
}
Shows policy names applied at individual controller actions so read and mutation permissions can differ. section 9.6
Listing 9.21 Creating authorization policies
using Microsoft.AspNetCore.Authorization;
builder.Services.AddAuthorization(options => #1
{
options.AddPolicy("AuthenticatedUsers", #2
policyBuilder => { #3
policyBuilder
.RequireAuthenticatedUser() #4
.AddAuthenticationSchemes( #5
JwtBearerDefaults.AuthenticationScheme); #6
});
options.AddPolicy("OnlyMe", #7
policyBuilder => {
policyBuilder
.RequireAuthenticatedUser()
.AddAuthenticationSchemes(
JwtBearerDefaults.AuthenticationScheme)
.AddRequirements(new OnlyMeRequirement()); #8
});
});
builder.Services.AddSingleton<IAuthorizationHandler, #9
OnlyMeRequirementHandler>(); #10
var app = builder.Build(); #11
Shows registration of named policies, authentication schemes, requirements, and the authorization handler service. section 9.6
Listing 9.22 Custom authorization requirement and handler
using Microsoft.AspNetCore.Authorization;
namespace ManningBooksApi;
public class OnlyMeRequirement : #1
IAuthorizationRequirement { } #2
public class OnlyMeRequirementHandler :
AuthorizationHandler<OnlyMeRequirement> #3
{
protected override Task HandleRequirementAsync( #4
AuthorizationHandlerContext context, #5
OnlyMeRequirement requirement)
{
if (context.User != null) #6
{
var emailClaim = context.User
.FindFirst("preferred_username"); #7
if (emailClaim != null
&& emailClaim.Value == "your@email.com") #8
{
context.Succeed(requirement); #9
}
}
return Task.CompletedTask; #10
}
}
Shows a custom requirement and handler that inspects an authenticated user's claim before calling Succeed. section 9.6












