Implementing authorization

This tutorial will walk you through step by step on how to authorize a user, display the UI for each user differently based on their identity. In this tutorial, you will discover:

  • Authorizing approaches.
  • Implementing authorize on route.
  • Implementing authorize on individual component.
  • Authorization rule overview.
  • Role based authorization rule.
  • Policy based authorization rule.
  • Common mistakes.
You can download the example code used in this topic on GitHub.

Authorizing approaches

There are 2 approaches when authorizing a user:

  • Authorize on route.
  • Authorize on individual component.

Authorize on route

This approach assumes every route in your website requires the user to be authenticated. Some routes can require more than authenticated user like require the user must have admin role, must be an adult, etc. You can also specify those requirements explicitly or remove the requirements entirely for each route eventually.

A route is bound to an independent component, that means if one of a route in the component requires some requirements, all the requirements will be applied to all other routes in that component.

With this approach, you will authorize your component as a whole. You can also combine authorize on route with authorize on individual component to authorize a part of UI.

The following image illustrates the authorize on route approach.

authorize-on-route.png

Authorize on individual component

This approach can segregate a component to many parts and display them differently per user. The following image illustrates the authorize on individual component approach.

authorize-on-individual-component.png


Implementing authorize on route

  1. Implement authentication.
  2. Register at App.razor. Replace RouteView with AuthorizeRouteView. For example:
<CascadingAuthenticationState>
    <Router AppAssembly="typeof(App).Assembly">
        <Found Context="routeData">
            <FocusOnNavigate RouteData="routeData" Selector="h1" />
            <AuthorizeRouteView RouteData="routeData" DefaultLayout="typeof(MainLayout)"></AuthorizeRouteView>
        </Found>
        <NotFound>
            ...
        </NotFound>
    </Router>
</CascadingAuthenticationState>
  1. Define NotAuthorized and Authorizing projected content inside the AuthorizeRouteView component. For example:
<AuthorizeRouteView RouteData="routeData" DefaultLayout="typeof(MainLayout)">
    <NotAuthorized>
        <div>You are not authorized.</div>
    </NotAuthorized>
    <Authorizing>
        <div>Authorizing...</div>
    </Authorizing>
</AuthorizeRouteView>
  1. Authorize entire website in the _Imports.razor.
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize]
  1. Allow at least 1 page to authorize the users. For example, add the following code to your login page.
@attribute [AllowAnonymous]

Implementing authorize on individual component

Wrap the content that needs to be authorized in the AuthorizeView component. For example:

<AuthorizeView>
    <Authorized><div>Authenticated</div></Authorized>
    <Authorizing><div>Loading...</div></Authorizing>
    <NotAuthorized><div>Not authenticated</div></NotAuthorized>
</AuthorizeView>

Authorization rule overview

A resource (route, component, button, etc) is protected by an authorization rule, when a user satisfied all the requirements in an authorization rule, the user will be able to access the resource. There are 2 types of authorization rule:

  • Role based rule.
  • Policy based rule.

Role based rule

The resource will be protected by a list of roles. When the user belongs to one of the role in the list, the rule is satisfied and the user can access the resource. The following steps will help you to use the role based rule.

  1. Set the user's roles in your GetAuthenticationStateAsync. For example:
public override Task<AuthenticationState> GetAuthenticationStateAsync()
{
    var claims = new List<Claim>
    {
        new (ClaimTypes.NameIdentifier,"Blazor School"),
        new (ClaimTypes.Role,"User"),
        new (ClaimTypes.Role,"PremiumUser")
    };
    ...
}
You must use System.Security.Claims.ClaimTypes.Role as the type of the claim.
  1. Set the required role for the resource.

Sample code for authorize on individual component approach:

<AuthorizeView Roles="User">
    <Authorized>
        <div>You are a user</div>
    </Authorized>
    <NotAuthorized>
        <div>You are not a user</div>
    </NotAuthorized>
</AuthorizeView>

You can also pass a list of roles to the AuthorizeView as follows:

<AuthorizeView Roles="BlazorSchoolSupporter,Admin">
    ...
</AuthorizeView>

Sample code for authorize on route approach:

@attribute [Authorize(Roles="BlazorSchoolSupporter")]

You can also pass a list of roles to the Authorize attribute as follows:

@attribute [Authorize(Roles="BlazorSchoolSupporter,Admin")]

Policy based rule

The policy based rule provides more flexible in authorization, you can use built-in requirements or define your custom requirements. For example, the user must be an adult, paid user to see some resources.

The policy based rule has 2 parts:

  • The requirement.
  • The requirement handler.

The requirement will yield the static data to authorize the user. For example, to consider a user is an adult, the user must be 18 or older. 18 in this case is the static data to authorize, and you can declare a property in the requirement to yield value 18. If you don't have any static data to authorize, you still need to create a requirement.

The requirement handler is bound to a requirement, and responsible to check if the user satisfies the rule or not. For example, you have the number 18 in the requirement, the requirement handler will read the user's age and compare the user's age to 18.

The following steps will help you to use the policy based rule.

  1. Set the user's data in your GetAuthenticationStateAsync. For example:
public override Task<AuthenticationState> GetAuthenticationStateAsync()
{
    var claims = new List<Claim>
    {
        new (ClaimTypes.NameIdentifier,"Blazor School"),
        new ("Age", 17.ToString())
    };
    ...
}
  1. Create the requirement. The requirement class will implement the IAuthorizationRequirement interface. For example:
public class AdultRequirement : IAuthorizationRequirement
{
    public int MinimumAgeToConsiderAnAdult { get; set; } = 18;
}
  1. Create the requirement handler. The requirement handler class will extend the AuthorizationHandler class. For example:
public class AdultRequirementHandler : AuthorizationHandler<AdultRequirement>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, AdultRequirement requirement)
    {
        int userAge = Convert.ToInt32(context.User.Claims.First(c => c.Type == "Age").Value);

        if(userAge >= requirement.MinimumAgeToConsiderAnAdult)
        {
            context.Succeed(requirement);
        }
        else
        {
            context.Fail();
        }

        return Task.CompletedTask;
    }
}
  1. Register the requirement handler in your Program.cs. For example:
builder.Services.AddScoped<IAuthorizationHandler, AdultRequirementHandler>();
  1. Register the policy in your Program.cs. For example:
builder.Services.AddAuthorizationCore(config =>
{
    config.AddPolicy("AdultPolicy", policy => policy.AddRequirements(new AdultRequirement()));
});

You can also add more requirements to a policy as follows:

builder.Services.AddAuthorizationCore(config =>
{
    config.AddPolicy("AdultAdminPolicy", policy =>
    {
        policy.AddRequirements(new AdultRequirement());
        policy.RequireRole("Admin");
    });
});
  1. Set the required policy for the resource.

Sample code for authorize on individual component approach:

<AuthorizeView Policy="AdultPolicy">
    <Authorized>
        <div>You are an adult</div>
    </Authorized>
    <NotAuthorized>
        <div>You are not an adult</div>
    </NotAuthorized>
</AuthorizeView>

Sample code for authorize on route approach:

@attribute [Authorize(Policy = "AdultPolicy")]

Pass data to a requirement handler

Sometimes, you need the data from the resource to authorize the user. For example, you are selling a list of books, and you only allow the users that are already bought the book to read. You will need to pass the book ID to the requirement handler, then the requirement handler will verify if the user has bought the book or not.

  1. Create the requirement. For example:
public class UnderAgeRestrictedRequirement : IAuthorizationRequirement
{
}
  1. Create the requirement handler. For example:
public class UnderAgeRestrictedRequirementHandler : AuthorizationHandler<UnderAgeRestrictedRequirement>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, UnderAgeRestrictedRequirement requirement)
    {
        int userAge = Convert.ToInt32(context.User.Claims.First(c => c.Type == "Age").Value);
        int minimumAgeRequired = Convert.ToInt32(context.Resource);

        if(userAge < minimumAgeRequired)
        {
            context.Fail(new (this, "User is underage"));
        }
        else
        {
            context.Succeed(requirement);
        }

        return Task.CompletedTask;
    }
}
  1. Register the requirement handler in your Program.cs. For example:
builder.Services.AddScoped<IAuthorizationHandler, UnderAgeRestrictedRequirementHandler>();
  1. Register the policy in your Program.cs. For example:
builder.Services.AddAuthorizationCore(config =>
{
    config.AddPolicy("UnderAgePolicy", policy => policy.AddRequirements(new UnderAgeRestrictedRequirement()));
});
  1. Set the policy for the resource, pass the authorizing data to the requirement handler in AuthorizeView.
<AuthorizeView Policy="UnderAgePolicy" Resource="10">
    <Authorized>
        <div>You are more than 10</div>
    </Authorized>
    <NotAuthorized>
        <div>You are not more than 10</div>
    </NotAuthorized>
</AuthorizeView>
The authorize on route approach does not support passing data to the requirement handler.

Common mistakes

In this section, we have collected some common mistakes from the Blazor School Discord Community.

Mistake #1: Accidentally remove the FocusOnNavigate component in the App.razor

When you are implementing the authorize on route approach, you will need to change your App.razor component. Remember to keep the FocusOnNavigate component when you are implementing this approach if you are not intended to remove it.

Mistake #2: Authorize the entire website including the login page

When you are implementing the authorize on route approach, you need to add [AllowAnonymous] attribute to your login page to let the user login to the website. Otherwise, the users have no way to access your website.

BLAZOR SCHOOL
Designed and built with care by our dedicated team, with contributions from a supportive community. We strive to provide the best learning experience for our users.
Docs licensed CC-BY-SA-4.0
Copyright © 2021-2025 Blazor School
An unhandled error has occurred. Reload 🗙