Caleb
Caleb

Reputation: 2267

Use Authorization Roles and Policies in Blazor WebAssembly with Identity?

I am using a Blazor WebAssembly 3.2-preview3 application scaffolded with Identity that has created the following 3 projects:

App.Client
App.Server
App.Shared

My IdentityUser implementation is called AppUser, and my ApiAuthorizationDbContext implementation is called AppDb

I have a role called Admin that has been assigned to administrators, and a Policy called RequireAdmin that checks for the Admin role. However, when I try to use an AuthorizeView in App.Client and view the page with an administrator, it does not show the link.

<AuthorizeView Policy="RequireAdmin">
    <Authorized>
        <a class="nav-link" href="admin">Admin</a>
    </Authorized>
</AuthorizeView>

How can I enable roles and policies in my Blazor WebAssembly application?

Upvotes: 6

Views: 4083

Answers (1)

Caleb
Caleb

Reputation: 2267

1. Create Roles and Policies in App.Shared

Add the Microsoft.AspNetCore.Authorization package to the App.Shared project

Add the following 2 classes in the App.Shared project to define Roles and Policies that will be used by the Client and Server.

Shared/RoleTypes.cs

namespace App.Shared
{
    public static class RoleTypes
    {
        public const string Admin = "Admin";
    }
}

Shared/PolicyTypes.cs

using Microsoft.AspNetCore.Authorization;

namespace App.Shared
{
    public static class PolicyTypes
    {
        public const string RequireAdmin = "RequireAdmin";

        public static AuthorizationOptions AddAppPolicies(this AuthorizationOptions options)
        {
            options.AddPolicy(RequireAdmin, policy =>
                policy.RequireRole(RoleTypes.Admin));
            return options;
        }
    }
}

2. Configure services in App.Server

Modify the Startup.cs file in the App.Server project to add your policies by calling the extension method that was just defined in App.Shared.

Also modify it to include the role claim in the openid scope.

Server/Startup.cs

using App.Shared;
...

namespace App.Server
{
    public class Startup
    {

        ...

        public void ConfigureServices(IServiceCollection services)
        {
            ...

            services.AddDefaultIdentity<AppUser>(options =>
                {
                    options.SignIn.RequireConfirmedAccount = true;
                })
                .AddRoles<IdentityRole>()
                .AddEntityFrameworkStores<AppDb>();

            services.AddIdentityServer()
                .AddApiAuthorization<AppUser, AppDb>(options =>
                {
                    // https://github.com/dotnet/AspNetCore.Docs/issues/17649
                    options.IdentityResources["openid"].UserClaims.Add("role");
                    options.ApiResources.Single().UserClaims.Add("role");
                });
            // Need to do this as it maps "role" to ClaimTypes.Role and causes issues
            JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("role");

            services.AddAuthentication()
                .AddIdentityServerJwt();

            services.AddAuthorization(options => options.AddAppPolicies());

            ...
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            ...

            app.UseAuthentication();
            app.UseAuthorization();
            app.UseIdentityServer();

            ...
        }
    }
}

3. Configure services in App.Client

Modify the Program.cs file in the App.Client project to add your policies by calling the extension method that was just defined in App.Shared. Also modify AddApiAuthorization to configure the role claim.

Client/Program.cs

using App.Client.Services;
using App.Shared;
...

namespace App.Client
{
    public class Program
    {
        public static async Task Main(string[] args)
        {
            ...

            builder.Services.AddAuthorizationCore(options => options.AddAppPolicies());
            // 2 calls to AddApiAuthorization are necessary in 3.2-preview3
            // should be fixed in 3.2-preview4
            // https://github.com/dotnet/aspnetcore/issues/19854
            // https://github.com/dotnet/AspNetCore.Docs/issues/17649#issuecomment-612442543
            builder.Services.AddApiAuthorization();
            builder.Services.AddApiAuthorization(options =>
            {
                options.UserOptions.RoleClaim = "role";
            });

            ...
        }
    }
}

Upvotes: 7

Related Questions