ASP.NET Core Documentation

Authentication and Authorization

ASP.NET Core Authentication & Authorization

This document provides a comprehensive guide to implementing authentication and authorization in ASP.NET Core applications. Securing your applications is paramount, and ASP.NET Core offers a flexible and robust framework to handle these concerns.

Note: Authentication determines who a user is, while authorization determines what actions that authenticated user is allowed to perform.

I. Understanding the Concepts

Authentication

Authentication is the process of verifying the identity of a user or client. ASP.NET Core uses an authentication middleware pipeline to handle this. Common authentication schemes include:

Authorization

Authorization is the process of determining whether an authenticated user has permission to perform a requested action or access a resource. ASP.NET Core provides several authorization models:

II. Implementing Authentication

Setting up Authentication Middleware

You configure authentication services in Program.cs (or Startup.cs in older versions). The primary methods are:

The authentication middleware is added to the HTTP request pipeline using app.UseAuthentication().


// Program.cs (Minimal APIs)
var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddRazorPages(); // Or AddControllers()

builder.Services.AddAuthentication("MyCookieAuth")
    .AddCookie("MyCookieAuth", options =>
    {
        options.LoginPath = "/Login"; // Path to the login page
        options.LogoutPath = "/Logout";
    });

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

// Add the authentication middleware
app.UseAuthentication();
app.UseAuthorization(); // Add this after UseAuthentication

app.MapRazorPages(); // Or app.MapControllers();

app.Run();
        

Handling User Login

Typically, you'll have a login page (e.g., a Razor Page or MVC controller) where users submit their credentials. Upon successful validation, you issue an authentication cookie:


// Example for a Razor Page handler
public async Task OnPostAsync(string returnUrl = null)
{
    if (ModelState.IsValid)
    {
        var user = await _userService.AuthenticateAsync(Input.Email, Input.Password);

        if (user != null)
        {
            var claims = new List
            {
                new Claim(ClaimTypes.Name, user.Username),
                new Claim(ClaimTypes.Email, user.Email)
                // Add role claims if applicable
            };

            var identity = new ClaimsIdentity(claims, "MyCookieAuth");
            var principal = new ClaimsPrincipal(identity);

            await HttpContext.SignInAsync("MyCookieAuth", principal);

            return LocalRedirect(returnUrl ?? "/");
        }
        ModelState.AddModelError(string.Empty, "Invalid login attempt.");
    }
    return Page();
}
        

III. Implementing Authorization

Role-Based Authorization

You can apply role-based authorization using the [Authorize] attribute on controllers or action methods. You can specify allowed roles:


[Authorize(Roles = "Admin")]
public class AdminController : Controller
{
    public IActionResult Index()
    {
        return View();
    }
}

[Authorize(Roles = "Admin, Editor")]
public IActionResult EditPost(int id)
{
    // ...
}
        

Policy-Based Authorization

Policy-based authorization offers greater flexibility. Define policies in Program.cs:


// Program.cs
builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("RequireAdministratorRole", policy =>
        policy.RequireRole("Administrator"));

    options.AddPolicy("MustBeOver18", policy =>
        policy.RequireAssertion(context =>
        {
            // Example: Check for a claim
            var ageClaim = context.User.FindFirst(c => c.Type == ClaimTypes.DateOfBirth);
            if (ageClaim == null) return false;

            var dob = DateTime.Parse(ageClaim.Value);
            var age = DateTime.Today.Year - dob.Year;
            if (age < 0) age -= 1; // Adjust for birthday not yet passed this year
            return age >= 18;
        }));
});
        

Apply policies using the [Authorize] attribute:


[Authorize(Policy = "RequireAdministratorRole")]
public class AdminDashboardController : Controller { ... }

[Authorize(Policy = "MustBeOver18")]
public IActionResult ViewRestrictedContent() { ... }
        

Custom Authorization Handlers

For complex scenarios, you can create custom IAuthorizationHandler implementations.

IV. Working with Claims and Identities

An Identity represents the authenticated user, and it contains a collection of Claims. Claims are key-value pairs that describe the user (e.g., `Name`, `Email`, `Role`, `DateOfBirth`).

Accessing User Information

Within controllers or Razor Pages, you can access the authenticated user's identity and claims via User property:


// In a Controller
public IActionResult Profile()
{
    var username = User.Identity.Name; // Or User.FindFirst(ClaimTypes.Name)?.Value
    var email = User.FindFirst(ClaimTypes.Email)?.Value;
    var isAdmin = User.IsInRole("Admin");

    return View(new { Username = username, Email = email, IsAdmin = isAdmin });
}
        

Important: Always use User.IsInRole() or policy-based authorization for robust security. Directly checking claims for authorization can be less secure if not implemented carefully.

V. Advanced Topics

Identity Framework

For managing users, passwords, roles, and their associated data, ASP.NET Core Identity is the recommended framework. It provides:

Token-Based Authentication (JWT Bearer)

Ideal for APIs and SPAs. Typically involves:

  1. A login endpoint that validates credentials and issues a JWT (JSON Web Token).
  2. Clients store the token and include it in the `Authorization` header (e.g., `Bearer `) for subsequent requests.
  3. The server's JWT Bearer authentication middleware validates the token.

Resource-Based Authorization

Authorization decisions are made against specific resources. This often involves custom authorization requirements and handlers.

Conclusion

ASP.NET Core provides a powerful and flexible set of tools for implementing authentication and authorization. By understanding the core concepts of authentication schemes, role-based, and policy-based authorization, you can build secure and robust web applications.

Continue exploring the official ASP.NET Core documentation for detailed examples and specific configurations for various scenarios.