Reputation: 2267
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
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