coolblue2000
coolblue2000

Reputation: 4908

Multiple Roles causing issues in Blazor

I add roles via the following code in the server project

 foreach (var userRole in userInfo.Roles)
            {
                claims.Add(new Claim(ClaimTypes.Role, userRole));
            }

            var token = new JwtSecurityToken(
                _config["JWTSettings:validIssuer"],
              _config["JWTSettings:validAudience"],
              claims,
              null,
              expires: DateTime.Now.AddMinutes(20),
              signingCredentials: credentials);

Now, If I only have one role then this works fine and the following code in the OnInitializedAsync method in a razor component

var t = await AuthState;
        var role1= t.User.IsInRole("admin");

leads to role1 being true.

However if I have multiple roles then role1 is then false (as it is for all the roles I add to the user) despite clearly being there!

Now, if I do the following in OnInitializedAsync

var t= await AuthState;
        var claimsList= t.User.Claims;
    foreach(var item in claimsList)
            {
                var s1 = item.Type;
                var s2 = item.Value;
                string asasas = string.Empty;
            }

I get a single claim that has a type of role and it has the following as its value

["admin","myrole2"]

on the server side I get a number of claims of type role, each with a single role as the value.

What on earth is going on?

Upvotes: 1

Views: 711

Answers (1)

Brian Parker
Brian Parker

Reputation: 14573

You need to transform your claims:

public class CustomUserFactory : AccountClaimsPrincipalFactory<RemoteUserAccount>
{
    public CustomUserFactory(IAccessTokenProviderAccessor accessor)
           : base(accessor)
    {
    }
    public override async ValueTask<ClaimsPrincipal> CreateUserAsync(
        RemoteUserAccount account,
        RemoteAuthenticationUserOptions options)
    {
        var user = await base.CreateUserAsync(account, options);
        ClaimsIdentity claimsIdentity = (ClaimsIdentity)user.Identity;
        if (account is not null) {
            MapArrayClaimsToMultipleSeparateClaims(account, claimsIdentity);
        }
        return user;
    }
    private void MapArrayClaimsToMultipleSeparateClaims(RemoteUserAccount account, ClaimsIdentity claimsIdentity)
    {
        foreach (var keyValuePair in account.AdditionalProperties) {
            var key = keyValuePair.Key;
            var value = keyValuePair.Value;
            if (value is not null &&
                value is JsonElement element && element.ValueKind == JsonValueKind.Array) {
                claimsIdentity.RemoveClaim(claimsIdentity.FindFirst(keyValuePair.Key));
                var claims = element.EnumerateArray()
                    .Select(x => new Claim(keyValuePair.Key, x.ToString()));
                claimsIdentity.AddClaims(claims);
            }
        }
    }
}

Program.cs in your client.

services.AddApiAuthorization().AddAccountClaimsPrincipalFactory<CustomUserFactory>();

Upvotes: 3

Related Questions