Implement User Claims o Blazor WASM

Posted 1 year ago by elshorbagy
Edited 1 year ago
0

Hello,

I have a page and I want to allow only users with a certain claim (CanViewContract) to access it. The api controller works as expected but the blazor side cannot read that claim, and always gives me an unauthorized error. 

I use Identity and SQL server.

I use this attribute at the top of the page:

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


This is my blazor programs.cs

var builder = WebAssemblyHostBuilder.CreateDefault(args);

builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after");

builder.Services.AddHttpClient("Assistant.ServerAPI", client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress))
    .AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();

// Supply HttpClient instances that include access tokens when making requests to the server project
builder.Services.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>().CreateClient("Assistant.ServerAPI"));

builder.Services.AddScoped<IInvitationClientService, InvitationClientService>();
builder.Services.AddScoped<IHttpClientContractService, HttpClientContractService>();

builder.Services.AddBlazoredLocalStorage();

builder.Services.AddLanguageContainer(Assembly.GetExecutingAssembly());

builder.Services.AddApiAuthorization();

builder.Services.AddAuthorizationCore(options =>
    options.AddPolicy("CanViewContract", policy => policy.RequireClaim("ViewContract", "true")));

builder.Services
    .AddBlazorise(options =>
    {
        options.Immediate = true;
    })
    .AddBootstrapProviders()
    .AddFontAwesomeIcons();


await builder.Build().RunAsync();
  • 1

    Based on what you have here, I suspect your main issue is that the claim you set to be required isn't there. Try adjusting the following service registrations in your server Program.cs to:

    builder.Services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
        .AddEntityFrameworkStores<ApplicationDbContext>()
        .AddClaimsPrincipalFactory<CustomUserClaimsPrincipalFactory>();
    
    builder.Services.AddIdentityServer()
        .AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options =>
        {
            options.IdentityResources["openid"].UserClaims.Add("CanViewContract");
            options.ApiResources.Single().UserClaims.Add("CanViewContract");
        });
        
    builder.Services.AddAuthorization(options =>
    {
        options.AddPolicy("CanViewContract", policy => policy.RequireClaim("CanViewContract", "true"));
    });


    Then create a new class called CustomUserClaimsPrincipalFactory (which is referenced in the Program.cs above) that looks like this (namespace and using directives will need adjusted to fit your app)

    using SomeBlazorApp.Server.Models;
    using Microsoft.AspNetCore.Identity;
    using Microsoft.Extensions.Options;
    using System.Security.Claims;
    
    namespace SomeBlazorApp.Server.Internal
    {
        internal class CustomUserClaimsPrincipalFactory : UserClaimsPrincipalFactory<ApplicationUser>
        {
            public CustomUserClaimsPrincipalFactory(
                UserManager<ApplicationUser> userManager,
                IOptions<IdentityOptions> optionsAccessor)
                : base(userManager, optionsAccessor)
            {
            }
    
            protected override async Task<ClaimsIdentity> GenerateClaimsAsync(ApplicationUser user)
            {
                var identity = await base.GenerateClaimsAsync(user);
    
                identity.AddClaim(new Claim("CanViewContract", "true"));
    
                return identity;
            }
        }
    }

    And adjust the service registration in the Program.cs for your WASM Client project to the following (notice the change of ViewContract to CanViewContract)

    builder.Services.AddAuthorizationCore(options =>
    {
        options.AddPolicy("CanViewContract", policy => policy.RequireClaim("CanViewContract", "true"));
    });

    Then see if this gets it running.

    Posted 1 year ago by selliott
Someone is typing...

Post a Reply

You must be logged in to add a new post.
Number of online users: 3
An error has occurred. This application may no longer respond until reloaded. Reload 🗙