asp.net-coreblazorclientwebassembly

The issue of having multiple roles on the client side in my Blazor WebAssembly project


<AuthorizeView Roles="@RulesAndRoles.Rules.FirstOrDefault(xd=> xd.Id ==1).Roles.ToString()">
<IconNavLink Href="Management" Icon="fa-star">
@localizer["Management"]
</IconNavLink>
</AuthorizeView>
<AuthorizeView Roles="@RulesAndRoles.Rules.FirstOrDefault(xd=> xd.Id == 2).Roles.ToString()">
<IconNavLink Href="Entity" Icon="fa-star">
@localizer["Entity"]
</IconNavLink>
</AuthorizeView>

The role claims of my JWT token are structured as follows.

"http://schemas.microsoft.com/ws/2008/06/identity/claims/role": [ "Administrator", "User" ],

I am fetching and populating the necessary roles from my static class RulesAndRoles that I pull from the database, and there is no issue with the system. However, things have changed, and now each user can have multiple roles.

In the above code, @RulesAndRoles.Rules.FirstOrDefault(xd => xd.Id == 1).Roles.ToString() returns a value like "Administrator,Manager". If a user has only "Administrator" or only "Manager" as their role, everything works fine, but if they have both roles at the same time, no AuthorizeView works properly.

How can I solve this issue?

Thank you in advance!

<AuthorizeView Roles="Administrator">
<Authorized>
<p>test admin</p>
</Authorized>
<NotAuthorized>
<AuthorizeView Roles="User">
<Authorized>
<p>test user</p>
</Authorized>
<NotAuthorized>
<p>xd</p>
</NotAuthorized>
</AuthorizeView>
</NotAuthorized>
</AuthorizeView>

I tried this, it works, but it's not very clean. In more complex areas, it makes things even more complicated.


Solution

  • You could seperate the jwt role in AuthenticationStateProvider like following:

    public class CustomAuthenticationStateProvider : AuthenticationStateProvider
    {
        private readonly IAccessTokenProvider _tokenProvider;
    
        public CustomAuthenticationStateProvider(IAccessTokenProvider tokenProvider)
        {
            _tokenProvider = tokenProvider;
        }
    
        public override async Task<AuthenticationState> GetAuthenticationStateAsync()
        {
            var tokenResult = await _tokenProvider.RequestAccessToken();
            if (tokenResult.TryGetToken(out var accessToken))
            {
                var handler = new JwtSecurityTokenHandler();
                var jwtToken = handler.ReadJwtToken(accessToken.Value);
    
                var identity = new ClaimsIdentity(jwtToken.Claims, "Bearer");
    
                // Extract and normalize role claims
                var roleClaims = jwtToken.Claims
                    .Where(c => c.Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/role")
                    .SelectMany(c => c.Value.Split(','))
                    .Select(role => new Claim(ClaimTypes.Role, role.Trim()));
    
                identity.AddClaims(roleClaims);
    
                var user = new ClaimsPrincipal(identity);
                return new AuthenticationState(user);
            }
    
            return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()));
        }
    }