Authorization

Back

Loading concept...

🏰 The Castle of Authorization: Who Gets In?

Imagine you have a magical castle with many rooms. Some rooms are for everyone, some are only for knights, and some are only for the king! Authorization is the guard at each door, deciding who can enter.

Authentication = “Who are you?” (showing your ID) Authorization = “What can you do?” (checking if you’re allowed in that room)


🎯 Authorization Overview

Think of authorization like a theme park:

  • You bought a ticket (authentication - you proved who you are)
  • But can you ride the VIP roller coaster? That depends on your wristband type (authorization)!
graph TD A["User Arrives"] --> B{Authenticated?} B -->|No| C["Go Login!"] B -->|Yes| D{Authorized?} D -->|No| E["Access Denied 🚫"] D -->|Yes| F["Welcome In! ✅"]

In ASP.NET, authorization happens AFTER authentication. First, we know who you are. Then, we check what you can do.


🔓 Simple Authorization

The easiest type! Like a door that only opens if you have ANY valid ticket.

The [Authorize] Attribute

Just add [Authorize] and boom - only logged-in users can enter!

[Authorize]
public class SecretController
    : Controller
{
    public IActionResult Index()
    {
        // Only logged-in users
        // can see this!
        return View();
    }
}

Allow Anonymous

Want to let EVERYONE see one page? Use [AllowAnonymous]:

[Authorize]
public class ProfileController
    : Controller
{
    [AllowAnonymous]
    public IActionResult PublicInfo()
    {
        // Anyone can see this!
        return View();
    }

    public IActionResult PrivateInfo()
    {
        // Must be logged in
        return View();
    }
}

🎈 Simple Example:

  • The school cafeteria is [Authorize] - only students allowed
  • The school entrance has [AllowAnonymous] - visitors can come in too!

👑 Role-Based Authorization

Like different colored wristbands at a water park:

  • 🟢 Green = Can use regular slides
  • 🟡 Yellow = Can use big slides
  • 🔴 Red (VIP) = Can use ALL slides!
[Authorize(Roles = "Admin")]
public class AdminController
    : Controller
{
    // Only Admins can enter!
    public IActionResult Dashboard()
    {
        return View();
    }
}

Multiple Roles (OR Logic)

Any of these roles can enter:

[Authorize(Roles = "Admin,Manager")]
public IActionResult Reports()
{
    // Admin OR Manager can see
    return View();
}

Require ALL Roles (AND Logic)

Stack the attributes - must have BOTH:

[Authorize(Roles = "Admin")]
[Authorize(Roles = "SuperUser")]
public IActionResult TopSecret()
{
    // Must be Admin AND SuperUser!
    return View();
}
graph TD A["User Request"] --> B{Has Role?} B -->|Admin| C["✅ Enter Admin Area"] B -->|Manager| D["✅ Enter Reports"] B -->|Guest| E["🚫 Access Denied"]

🏷️ Authorization Attributes

These are like sticky labels you put on doors to say who can enter!

Where Can You Put Them?

Level What It Does
Controller Protects ALL actions inside
Action Protects just ONE method
Global Protects the WHOLE app

Controller Level

[Authorize] // Protects everything!
public class AccountController
    : Controller
{
    // All methods here need login
}

Action Level

public class HomeController
    : Controller
{
    public IActionResult Index()
    {
        return View(); // Anyone!
    }

    [Authorize]
    public IActionResult Profile()
    {
        return View(); // Login needed!
    }
}

Global Level (in Program.cs)

builder.Services
    .AddAuthorization(options =>
{
    options.FallbackPolicy =
        new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .Build();
});

Now EVERYTHING needs login by default!


📜 Claims-Based Authorization

Claims are like facts written on your ID card:

  • Name: “Alice”
  • Age: 25
  • Department: “Engineering”
  • HasDrivingLicense: true

You can check these facts to allow access!

// In Program.cs
builder.Services
    .AddAuthorization(options =>
{
    options.AddPolicy("CanDrive",
        policy => policy
        .RequireClaim("DrivingLicense"));
});
[Authorize(Policy = "CanDrive")]
public IActionResult RentCar()
{
    // Only if you have
    // a DrivingLicense claim!
    return View();
}

Claim with Specific Value

options.AddPolicy("Over18",
    policy => policy
    .RequireClaim("Age", "18", "19",
        "20", "21")); // or higher

🎈 Real Life Example:

  • Claim: “EmployeeType” = “FullTime”
  • Only full-time employees can access the bonus calculator!

📋 Policy-Based Authorization

Policies are like rulebooks - combine multiple requirements into one name!

Creating a Policy

builder.Services
    .AddAuthorization(options =>
{
    options.AddPolicy("AdminOnly",
        policy => policy
        .RequireRole("Admin")
        .RequireClaim("Department",
            "IT"));
});

Using a Policy

[Authorize(Policy = "AdminOnly")]
public IActionResult ServerSettings()
{
    // Must be Admin role
    // AND IT department!
    return View();
}

Built-in Requirements

Requirement What It Checks
RequireRole() User has this role
RequireClaim() User has this claim
RequireUserName() Specific username
RequireAssertion() Custom true/false check

Custom Assertion

options.AddPolicy("WorkHours",
    policy => policy
    .RequireAssertion(context =>
{
    var hour = DateTime.Now.Hour;
    return hour >= 9 && hour <= 17;
}));

This only allows access between 9 AM and 5 PM! 🕐


🛠️ Custom Authorization Handlers

When the built-in checks aren’t enough, build your own!

Step 1: Create a Requirement

public class MinimumAgeRequirement
    : IAuthorizationRequirement
{
    public int MinAge { get; }

    public MinimumAgeRequirement(
        int minAge)
    {
        MinAge = minAge;
    }
}

Step 2: Create a Handler

public class MinimumAgeHandler
    : AuthorizationHandler
    <MinimumAgeRequirement>
{
    protected override Task
        HandleRequirementAsync(
        AuthorizationHandlerContext ctx,
        MinimumAgeRequirement req)
    {
        var dob = ctx.User
            .FindFirst("DateOfBirth");

        if (dob != null)
        {
            var birthDate =
                DateTime.Parse(dob.Value);
            var age = DateTime.Today.Year
                - birthDate.Year;

            if (age >= req.MinAge)
            {
                ctx.Succeed(req);
            }
        }
        return Task.CompletedTask;
    }
}

Step 3: Register Everything

// In Program.cs
builder.Services
    .AddSingleton
    <IAuthorizationHandler,
     MinimumAgeHandler>();

builder.Services
    .AddAuthorization(options =>
{
    options.AddPolicy("AtLeast21",
        policy => policy.Requirements
        .Add(new MinimumAgeRequirement(21)));
});

Step 4: Use It!

[Authorize(Policy = "AtLeast21")]
public IActionResult BuyBeer()
{
    return View();
}
graph TD A["Request Arrives"] --> B["Find Handler"] B --> C["Handler Checks Age"] C -->|Age >= 21| D["ctx.Succeed ✅"] C -->|Age < 21| E["Access Denied 🚫"]

🎁 Resource-Based Authorization

Sometimes you need to check: “Can THIS user edit THIS specific document?”

It’s not just about WHO you are, but WHAT you’re trying to access!

The Service

public class DocumentService
{
    private readonly
        IAuthorizationService _auth;

    public DocumentService(
        IAuthorizationService auth)
    {
        _auth = auth;
    }

    public async Task<IActionResult>
        Edit(Document doc,
             ClaimsPrincipal user)
    {
        var result = await _auth
            .AuthorizeAsync(user, doc,
                "EditDocument");

        if (result.Succeeded)
        {
            // Can edit!
        }
        else
        {
            // Cannot edit!
        }
    }
}

The Requirement

public class DocumentOwnerRequirement
    : IAuthorizationRequirement
{ }

The Handler

public class DocumentOwnerHandler
    : AuthorizationHandler
    <DocumentOwnerRequirement, Document>
{
    protected override Task
        HandleRequirementAsync(
        AuthorizationHandlerContext ctx,
        DocumentOwnerRequirement req,
        Document doc)
    {
        var userId = ctx.User
            .FindFirst(ClaimTypes.NameIdentifier)
            ?.Value;

        if (doc.OwnerId == userId)
        {
            ctx.Succeed(req);
        }

        return Task.CompletedTask;
    }
}

🎈 Real Life Example:

  • Alice can edit HER documents
  • Bob can edit HIS documents
  • Neither can edit each other’s!

🎨 Summary: The Authorization Family

Type Best For Example
Simple “Any logged-in user” [Authorize]
Role-based User groups Admin, Manager
Claims-based User facts/properties Age, Department
Policy-based Combined rules Admin + IT Department
Custom Handlers Complex logic Age calculation
Resource-based Per-item access “Your own documents”

🚀 Quick Tips

  1. Start Simple - Use [Authorize] first, add complexity when needed
  2. Policies are Reusable - Define once, use everywhere
  3. Combine Wisely - Role + Claims = Powerful policies
  4. Think Resources - Sometimes it’s about WHAT, not just WHO
  5. Handler = Custom Logic - When built-ins aren’t enough

🏆 You did it! Now you know how to guard your castle with ASP.NET Authorization. From simple locks to complex guard systems, you have all the tools you need!

graph TD A["You!"] --> B["Simple Auth"] B --> C["Roles"] C --> D["Claims"] D --> E["Policies"] E --> F["Custom Handlers"] F --> G["Resource-Based"] G --> H["🏆 Master!"]

Loading story...

Story - Premium Content

Please sign in to view this story and start learning.

Upgrade to Premium to unlock full access to all stories.

Stay Tuned!

Story is coming soon.

Story Preview

Story - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.