Why does authorizeview roles="admin" crash my app?

659 views Asked by At

here is a brief description of my app: VS2019 Blazor App, Individual User Authentication, netcore hosted.

What the goal is: Role based Authorization with HIDDEN links for non authorized users.

After reading up on Role based authorization I ended up with changing my Service as follows: enter image description here

I Seeded my db with an admin user and 2 roles like so: enter image description here

Everthing worked great. My trouble started when I tried to hide non-admin links in the 'NavMenu.razor' page using AuthorizeView Roles="admin": enter image description here

After that change my application just closes down throwing the following exceptions: enter image description here

I really do not know where to look. 'AuthorizeView' works, but 'AuthorizeView Roles="admin"' throws the system for a loop.

It may have something to do with the way claims deal with roles, but I need someone experienced to help me sort this out or suggest another way to achieve the goal.

Thanks!

PS: Sorry about all the pics, I was having problems formatting the Error Logs and the html, so I just pasted images.

1

There are 1 answers

6
enet On BEST ANSWER

It seems to me that the issue may be with IdentityServer...

Try the following code and see if it can solve the issue. Place the following settings in the client's Main method:

 builder.Services.AddApiAuthorization()
                .AddAccountClaimsPrincipalFactory<RolesClaimsPrincipalFactory>();

Create a new class: RolesClaimsPrincipalFactory.cs

    using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication.Internal;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Text.Json;
using System.Threading.Tasks;


 public class RolesClaimsPrincipalFactory : AccountClaimsPrincipalFactory<RemoteUserAccount>
    {
        public RolesClaimsPrincipalFactory(IAccessTokenProviderAccessor accessor) : base(accessor)
        {
        }
        
        public override async ValueTask<ClaimsPrincipal> CreateUserAsync(RemoteUserAccount account, RemoteAuthenticationUserOptions options)
        {
            var user = await base.CreateUserAsync(account, options);
            if (user.Identity.IsAuthenticated)
            {
                var identity = (ClaimsIdentity)user.Identity;
                var roleClaims = identity.FindAll(identity.RoleClaimType);
                if (roleClaims != null && roleClaims.Any())
                {
                    foreach (var existingClaim in roleClaims)
                    {
                        identity.RemoveClaim(existingClaim);
                    }

                    var rolesElem = account.AdditionalProperties[identity.RoleClaimType];
                    if (rolesElem is JsonElement roles)
                    {
                        if (roles.ValueKind == JsonValueKind.Array)
                        {
                            foreach (var role in roles.EnumerateArray())
                            {
                                identity.AddClaim(new Claim(options.RoleClaim, role.GetString()));
                            }
                        }
                        else
                        {
                            identity.AddClaim(new Claim(options.RoleClaim, roles.GetString()));
                        }
                    }
                }
            }

            return user;
        }
    }

It may have something to do with the way claims deal with roles

Exactly...

, but I need someone experienced to help me sort this out or suggest another way to achieve the goal.

Consider using policy-based (claims-based) authorization even if you'd succeed to solve this issue. As a matter of fact, roles-based authorization is internally implemented as claims-based