Невозможно сопоставить утверждение групп Okta с заявлением о ролях в клиенте Blazor WASM

Проблема

Я пытаюсь использовать компонент AuthorizeView в Blazor, чтобы скрыть / показать разные части страницы в зависимости от роли пользователя. Я использую OIDC, подключенный к OKTA, в качестве поставщика аутентификации.

По умолчанию OKTA возвращает область Roles как утверждение Groups в пределах id_token. Я попытался заставить провайдер аутентификации просматривать заявки групп на роли, как показано в приведенном ниже коде.

Моя тестовая учетная запись имеет соответствующие разрешения, как я вижу в заявке Группы. Я не могу заставить это сопоставление работать.

У кого-нибудь были подобные проблемы и / или нашел решение для этого?

Образец кода

-- Program.cs --
public static async Task Main(string[] args)
{
    ...

    builder.Services.AddOidcAuthentication(options =>
    {
        options.ProviderOptions.Authority = "***";
        options.ProviderOptions.ClientId = "***";
        options.ProviderOptions.DefaultScopes.Add("roles");
        options.ProviderOptions.ResponseType = "token id_token";
        
        options.UserOptions.RoleClaim = "groups";
        options.UserOptions.NameClaim = "name";
    });

    ....
}

-- MyPage.razor --
<AuthorizeView Roles="Admin">
    <Authorized>
        Authorized
    </Authorized>
    <NotAuthorized>
        Not Authorized
    </NotAuthorized>
</AuthorizeView>

person Doron Epstein    schedule 22.07.2020    source источник
comment
Вы проверили токен, чтобы увидеть, есть ли там утверждения ролей? Если да, то разделяются ли они запятыми или отдельные претензии?   -  person Brian Parker    schedule 22.07.2020
comment
@Orak - возвращает утверждение под названием groups, которое содержит массив ролей, разделенных запятыми.   -  person Doron Epstein    schedule 22.07.2020


Ответы (1)


Решение

Я нашел следующую статью: http://blazorhelpwebsite.com/Blog/tabid/61/EntryId/4376/Implementing-Roles-In-Blazor-WebAssembly.aspx, в котором объясняется, как использовать настраиваемую фабрику субъектов претензий.

Я скопировал код из статьи и скорректировал его под свои нужды.

Роли

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)
        {
            return user;
        }

        var identity = (ClaimsIdentity) user.Identity;
        var roleClaims = identity.FindAll(claim => claim.Type == "groups");
        if (roleClaims == null || !roleClaims.Any())
        {
            return user;
        }

        foreach (var existingClaim in roleClaims)
        {
            identity.RemoveClaim(existingClaim);
        }

        var rolesElem = account.AdditionalProperties["groups"];
        if (!(rolesElem is JsonElement roles))
        {
            return user;
        }

        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;
    }
}

Program.cs

public class Program
{
    public static async Task Main(string[] args)
    {
        ...

        builder.Services.AddOidcAuthentication(options =>
        {
            options.ProviderOptions.Authority = ******;
            options.ProviderOptions.ClientId = ******;
            options.ProviderOptions.DefaultScopes.Add("roles");
            options.ProviderOptions.ResponseType = "token id_token";

            options.UserOptions.RoleClaim = "role";
        }).AddAccountClaimsPrincipalFactory<RolesClaimsPrincipalFactory>();

        ...
    }
}

Ключевые выводы

  1. Вы должны указать RoleClaim options.UserOptions.RoleClaim = "role";. Если вы этого не сделаете, вы получите исключение NullReferenceException.
  2. Реализация настраиваемого участника утверждений выполняется с помощью метода расширения AddAccountClaimsPrincipalFactory<T>().
  3. Это решение кажется нишевым для OKTA Auth, Blazor WASM и OIDC.
person Doron Epstein    schedule 22.07.2020