Role-Based, Policy-Based & Claims-Based Security
Go beyond simple authentication — implement fine-grained authorization that controls exactly who can do what in your ASP.NET Core applications.
What You'll Learn
- • Role-based authorization with
[Authorize(Roles = "...")] - • Custom policies with requirements and handlers
- • Claims transformation to enrich user identity
- • Resource-based authorization for ownership checks
🏢 Real-World Analogy
Think of authorization like a building's security system. Roles are like key cards — "Employee" gets you in the front door, "Manager" unlocks the executive floor. Policies are like conditional rules — "only verified employees over 18 can access the lab." Claims are facts printed on your badge — department, clearance level — that guards check before letting you through.
Role-Based Authorization (RBAC)
The simplest authorization model. Assign roles to users and restrict endpoints by role. Use comma-separated roles for OR logic, or stack [Authorize] attributes for AND logic.
Role-Based Authorization
Restrict API endpoints by user role with [Authorize(Roles)].
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
// Role-Based Authorization — restrict by role
[ApiController]
[Route("api/[controller]")]
public class AdminController : ControllerBase
{
// Only users with "Admin" role can access
[HttpGet("dashboard")]
[Authorize(Roles = "Admin")]
public IActionResult GetDashboard()
{
return Ok(new { Message = "Welcome, Admin!", Time = DateTime.UtcNow });
}
// Multiple roles — comma-separated (OR lo
...Policy-Based Authorization
Policies let you combine multiple requirements — claims, roles, custom logic — into named rules. This is the recommended approach for anything beyond simple role checks.
Custom Policies & Requirements
Create policies that combine claim checks, age verification, and custom logic.
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.DependencyInjection;
// Program.cs — Register policies
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthorization(options =>
{
// Simple claim-based policy
options.AddPolicy("EmailVerified", policy =>
policy.RequireClaim("email_verified", "true"));
// Age-based policy with custom requirement
options.AddPolicy("AtLeast18", policy =>
policy.Requirements.Add(new MinimumAg
...Claims Transformation
Enrich a user's identity at login by loading additional claims from your database. This lets you centralize authorization data without querying the DB on every request.
Claims Transformation
Load extra claims from the database and attach them to the user identity.
using System.Security.Claims;
using Microsoft.AspNetCore.Authentication;
// Claims Transformation — enrich identity at login
public class CustomClaimsTransformation : IClaimsTransformation
{
private readonly IUserService _userService;
public CustomClaimsTransformation(IUserService userService)
{
_userService = userService;
}
public async Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
{
var identity = (ClaimsIdentity)principal.Identity!;
...Resource-Based Authorization
Sometimes you need to check if a user owns or has access to a specific resource — not just whether they have a role. Resource-based authorization passes the resource object to the handler.
Resource-Based Authorization
Check document ownership before allowing updates.
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authorization.Infrastructure;
// Resource-based authorization — check ownership
public class DocumentAuthorizationHandler
: AuthorizationHandler<OperationAuthorizationRequirement, Document>
{
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context,
OperationAuthorizationRequirement requirement,
Document resource)
{
var userId = context.User.FindFirst(
...Pro Tip
Use FallbackPolicy to require authentication by default, then use [AllowAnonymous] on public endpoints. This prevents accidentally exposing private endpoints.
Common Mistakes
- • Checking roles in controller logic instead of using policies — hard to maintain
- • Forgetting to register
IAuthorizationHandlerin DI — handler never runs - • Using OR when you need AND — comma-separated roles means any role matches
Lesson Complete!
You've mastered role-based, policy-based, and claims-based security. Next, learn caching strategies to boost your application's performance.
Sign up for free to track which lessons you've completed and get learning reminders.