Использование ролей в Blazor Wasm

#azure-active-directory #jwt #blazor-webassembly

#azure-active-directory #jwt #blazor-webassembly

Вопрос:

Я настроил аутентификацию с использованием единого принципа Azure AD. Использование ролей приложений для авторизации.

API является asp.net ядро 3.1 с клиентом swagger. Все протестировано, и все работает. Клиент Blazor может войти в систему. Но пользователь.У Identity нет утверждений о роли, поэтому AuthorizeView не работает.

Итак, что я упускаю? пакет nuget или мне нужно сопоставить роли с пользовательской учетной записью пользователя?

Это мой токен jwt с 3 ролями

 {
"aud": "https://testacompany.onmicrosoft.com/customeredit-api",
"iss": "https://sts.windows.net/8506d453-347c-4239-adf7-602ca98f4853/",
"iat": 1614587145,
"nbf": 1614587145,
"exp": 1614591045,
"acr": "1",
"aio": "AUQAu/8TAAAAf2oBifx9vVtfPJXmlKP/MOzvpF3Flcnlt2BLFHe8B9K2NUFrQF4XP69vRu8voLMK5eo8zGgIl/aTdHOnrqmGaQ==",
"amr": [
    "pwd"
],
"appid": "1a454d3f-329b-490d-b0fe-521bf6f61478",
"appidacr": "0",
"email": "xxx@acompany.dk",
"given_name": "Martin",
"idp": "https://sts.windows.net/3443ebe9-de49-471a-b7e5-9f9abfafac0c/",
"ipaddr": "131.165.55.123",
"name": "Martin Andersen",
"oid": "f121e73d-f5d8-436a-aef5-954cd286e80e",
"rh": "0.AAAAU9QGhXw0OUKt92AsqY9IUz9NRRqbMg1JsP5SG_b2FHiBAOY.",
"roles": [
    "EditCustomer",
    "EditAgreement",
    "Reader"
],
"scp": "Api.Access",
"sub": "oxMQxcyNNgU-fZMto4xwOOwrI18mlUgM1GyyNhAFmDQ",
"tid": "8506d453-347c-4239-adf7-602ca98f4853",
"unique_name": "xxx@acompany.dk",
"uti": "K-zFcTY_mUG6RNzI-FdgAA",
"ver": "1.0"
}
 

В Blazor Program.cs

 b.Services.AddMsalAuthentication<RemoteAuthenticationState, CustomUserAccount>(options =>
{
    options.UserOptions.RoleClaim = "role";
    b.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);
    options.ProviderOptions.DefaultAccessTokenScopes.Add("https://testacompany.onmicrosoft.com/customeredit-api/Api.Access");
}).AddAccountClaimsPrincipalFactory<RemoteAuthenticationState,CustomUserAccount ,CustomUserFactory>();

b.Services.AddOptions();
b.Services.AddAuthorizationCore();
 

Я также попытался создать CustomUserFactory

 public class CustomUserFactory : AccountClaimsPrincipalFactory<CustomUserAccount>
{
    public CustomUserFactory(IAccessTokenProviderAccessor accessor)
        : base(accessor)
    {
    }

    public override async ValueTask<ClaimsPrincipal> CreateUserAsync(
        CustomUserAccount account,
        RemoteAuthenticationUserOptions options)
    {
        var user = await base.CreateUserAsync(account, options);

        Console.WriteLine($"User IsAuthenticated: {user.Identity.IsAuthenticated}");
        
        if (user.Identity.IsAuthenticated)
        {
            var identity = (ClaimsIdentity)user.Identity;
            var roleClaims = identity.FindAll(identity.RoleClaimType).ToArray();
            if (roleClaims.Any())
            {
                foreach (var existingClaim in roleClaims)
                {
                    identity.RemoveClaim(existingClaim);
                }

                var rolesElem = account.AdditionalProperties[identity.RoleClaimType];

                if (rolesElem is JsonElement roles)
                {
                    Console.WriteLine($"JsonElement: {rolesElem}");
                    if (roles.ValueKind == JsonValueKind.Array)
                    {
                        
                        foreach (var role in roles.EnumerateArray())
                        {
                            Console.WriteLine($"role: {role.GetString()}");
                            identity.AddClaim(new Claim(options.RoleClaim, role.GetString()));
                        }
                    }
                    else
                    {
                        Console.WriteLine($"roles: {roles.GetString()}");
                        identity.AddClaim(new Claim(options.RoleClaim, roles.GetString()));
                    }
                }
            }
        }
        return user;
    }
}
 

Но я думаю, что мне нужно проанализировать необработанный jwt и сопоставить роли моему пользователю.
Итак, как я могу получить доступ к токену jwt?

Комментарии:

1. Вы уже на портале Azure предоставили роль вошедшему в систему пользователю?

2. Пользователи находятся в группах, а роли приложений подключены к группам. Клиент Swagger работает с использованием ролей

3. Вы ссылались на docs.microsoft.com/en-us/aspnet/core/blazor/security /…

4. Да, я прочитал это и попробовал «groupMembershipClaims»: «Все» и пользовательский профиль. В итоге был проанализирован токен и добавлены роли в качестве утверждений

5. Похоже, эта проблема решена? Можете ли вы добавить ответ, который может помочь людям, у которых может возникнуть такая же проблема?

Ответ №1:

Эта реализация должна решить вашу проблему. Я надеюсь, что это будет включено в будущие шаблоны .net 6 .

В Blazor Program.cs

 builder.Services.AddMsalAuthentication<RemoteAuthenticationState, CustomUserAccount>
            (options =>
            {
                builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);
                options.ProviderOptions.DefaultAccessTokenScopes.Add("https://testacompany.onmicrosoft.com/customeredit-api/Api.Access");
                options.UserOptions.RoleClaim = "role";
            }).AddAccountClaimsPrincipalFactory<RemoteAuthenticationState, CustomUserAccount, CustomUserFactory>();
 

Создайте пользовательскую фабрику пользователей:

 public class CustomUserFactory : AccountClaimsPrincipalFactory<CustomUserAccount>
{
    public CustomUserFactory(IAccessTokenProviderAccessor accessor)
        : base(accessor)
    {
     
    }

    public async override ValueTask<ClaimsPrincipal> CreateUserAsync(CustomUserAccount account, RemoteAuthenticationUserOptions options)
    {
        var initialUser = await base.CreateUserAsync(account, options);

        if (initialUser.Identity.IsAuthenticated)
        {
            var userIdentity = (ClaimsIdentity)initialUser.Identity;
            if (account?.Roles?.Length > 0)
            {
                foreach (var role in account?.Roles)
                {
                    userIdentity.AddClaim(new Claim("role", role));
                }
            }
            if (account?.Groups?.Length > 0)
            {
                foreach (var group in account?.Groups)
                {
                    userIdentity.AddClaim(new Claim("group", group));
                }
            }
        }

        return initialUser;
    }
}
 

Создайте учетную запись CustomUserAccount:

 public class CustomUserAccount : RemoteUserAccount
{
    [JsonPropertyName("groups")]
    public string[] Groups { get; set; }

    [JsonPropertyName("roles")]
    public string[] Roles { get; set; }
}
 

Роли теперь доступны через компонент AuthorizeView (на вашей странице.razor):

  <AuthorizeView Roles="EditCustomer"> Content only available to EditCustomer Role</AuthorizeView>