Authorization with Role and Policy

On a complex website, there will be many roles or policies that each role and policy have their own privileges. For example, assuming you only want people with admin roles to access the admin panel, this is called authorization with role. Another case would be assuming you only want users with age 18 or older to access some pages on the website, this is called authorization with policy.

You can download the example code used in this topic on GitHub.

Prerequisites

To understand this guide, you need to have some basic knowledge:


Authorization with Role

As the name suggested, you authorize people with their roles. Assuming you have a resource and you define which role can access that resource, then any user with one or more roles in the role list can have access to the resource.

Setting up a protected page

Create a new AdminPanel.razor component in the Page folder.

@page "/admin-panel"

<AuthorizeView Roles="Admin,SuperAdmin">
    <NotAuthorized>
        You must be Admin or Super Admin to access this page.
    </NotAuthorized>
    <Authorized>
        <h1>Admin panel</h1>
    </Authorized>
</AuthorizeView>

In this example, you are specifying users with either "Admin" or "SuperAdmin" can access the page. Users without any of those roles won't be able to access the page.

Set roles for the user

You need to set the roles for the user in the ClaimPrincipal object of GetAuthenticationStateAsync method. Continuation from the example in Authentication and authorization. Add roles as strings to the claim as follows:

private ClaimsIdentity CreateIdentityFromUser(User user)
{
    var result = new ClaimsIdentity(new Claim[]
    {
        new (ClaimTypes.Name, user.Username),
        new (ClaimTypes.Hash, user.Password),
    }, "BlazorSchool");
            
    var roles = _dataProviderService.GetUserRoles(user);

    foreach(string role in roles)
    {
        result.AddClaim(new (ClaimTypes.Role, role));
    }

    return result;
}

After that, use the ClaimsIdentity we just created in the above method to create a new AuthenticationState in the method GetAuthenticationStateAsync.

Users with one of the roles Admin or SuperAdmin can now access the AdminPanel.razor component.


Authorization with Policy

Unlike Role authorization, Policy authorization is used for complex scenarios. Policy authorization allows you to combine many conditions into one policy and will allow the user to enter if all the conditions are satisfied. For example, assuming you only want users older than 18 and also a premium member to buy alcohol.

Customizing authorization rules

An essential feature of authorization by policy is to customize the authorization rules. The following steps demonstrate how to authorize users over 18.

  1. Create a requirement class.
public class AdultRequirement : IAuthorizationRequirement
{
    public static string ClaimName => "Age";
}
  1. Create a requirement handler class.
public class AdultRequirementHandler : AuthorizationHandler<AdultRequirement>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, AdultRequirement requirement)
    {
        var (value, isSuccess) = TryRetrieveValue(context);

        if (isSuccess && value >= 18)
        {
            context.Succeed(requirement);
        }
        else
        {
            context.Fail();
        }

        return Task.CompletedTask;
    }

    private static (int, bool) TryRetrieveValue(AuthorizationHandlerContext context)
    {
        string value = context.User.FindFirst(ct => ct.Type == AdultRequirement.ClaimName)?.Value;

        if (!string.IsNullOrEmpty(value))
        {
            int age = Convert.ToInt32(value);

            return (age, true);
        }
        else
        {
            return (0, false);
        }
    }
}

In this class, we will get the value of a claim with the name "Age" and compare that value to 18. If the condition is satisfactory, we call context.Succeed(requirement). Otherwise, we call context.Fail().

Customize authorization rules by authorizing resource data

In some cases, you need the authorizing resource data to authorize users. For example, you have a toy store and each toy on the store has different age restrictions. In that case, you need to pass the age restriction to the AuthorizationHandler. The following code demonstrates how to authorize a user by comparing the user data to the authorizing resource data.
public class OverAgeRequirementHandler : AuthorizationHandler<OverAgeRequirement>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, OverAgeRequirement requirement)
    {
        var (value, isSuccess) = TryRetrieveValue(context);
        int minAge = Convert.ToInt32(context?.Resource ?? 0);

        if (isSuccess && value >= minAge)
        {
            context.Succeed(requirement);
        }
        else
        {
            context.Fail();
        }

        return Task.CompletedTask;
    }

    private static (int, bool) TryRetrieveValue(AuthorizationHandlerContext context)
    {
        ...
    }
}

Set user data for authorization

In the AdultRequirementHandler you just created, you will get data from the claim to authorize it. In order to do that, you need to put the data in the claim when a user logins. You need to update your CreateIdentityFromUser method:

private ClaimsIdentity CreateIdentityFromUser(User user)
{
    var result = new ClaimsIdentity(new Claim[]
    {
        ...
        new (AdultRequirement.ClaimName, user.Age.ToString()),
        new ("IsPremiumMember", user.IsPremiumMember.ToString())
    }, "BlazorSchool");
    ...
}

In this method, we also include the IsPremiumMember to demonstrate how to combine authorization rules later.

Defining a policy

A policy is defined by a combination of rules. You can define many policies and use them across your website to authorize users. You need to define a policy in ConfigureServices method in Startup.cs.

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddAuthorization(config =>
    {
        config.AddPolicy("CanBuyAlcohol", policy =>
        {
            policy.AddRequirements(new AdultRequirement());
            policy.RequireClaim("IsPremiumMember", true.ToString());
        });
    });
}

In this example, you are authorizing people for 2 conditions: they must be over 18 and must be a premium member. The first parameter of config.AddPolicy(name, configurePolicy) method is the name of the policy, which is CanBuyAlcohol and the second parameter is all the conditions of this policy. Later on, you will use the name CanBuyAlcohol to use this policy.

Since AdultRequirement is a custom rule, you must register its requirement handler as well.

services.AddSingleton<IAuthorizationHandler, AdultRequirementHandler>();

Using the policy to authorize users

Once you have completed all the steps above, you will be able to use the CanBuyAlcohol policy in any component on your website as long as it is wrapped by CascadingAuthenticationState component in App.razor. To use the policy, specify its name in the AuthorizeView component as follows:

<AuthorizeView Policy="CanBuyAlcohol">
    <Authorized>
        <h3>Welcome to the Alcohol Store</h3>
    </Authorized>
    <NotAuthorized>
        You don't have permission to see this.
    </NotAuthorized>
</AuthorizeView>

Passing authorizing resource data

If you need the resource data to authorize the user then you can pass resource data to the AuthorizeView by using Resource parameter. Then AuthorizeView will pass that data to the AuthorizationHandler. You can pass authorizing resource data as follows:

@foreach (Toy toy in SimulatedDataProviderService.Toys)
{
    <h1>@toy.Name</h1>
    <AuthorizeView Policy="OverAge" Resource="toy.AgeRequired">
        <Authorized>
            <button>Buy this toy</button>
        </Authorized>
        <NotAuthorized>
            Restricted
        </NotAuthorized>
    </AuthorizeView>
}
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 🗙