Как авторизовать роль пользователя на стороне клиента blazor wasm?

Среды

  • Asp.Net Core 5.0
  • Приложение Blazor WebAssembly (хостинг Asp.Net Core)
  • Asp.Net Core Identity (с Identity Server 4)

Проблема

Я хочу использовать авторизацию на основе ролей между стороной сервера и стороной клиента.

Я могу войти в систему правильно, и UserManager.IsInRoleAsync(user, "admin") вернет True на стороне сервера.

Но ни @attribute [Authorize(Roles = "admin")], ни <AuthorizeView Roles="admin"> не работают на стороне клиента. Также User.Identity.IsInRole("admin") возвращает False на стороне клиента.

Как мне получить роль пользователя на стороне клиента?

Коды

Server.csproj

// Startup.ConfigureServices()

services.AddDefaultIdentity<ApplicationUser>(options =>
{
    options.SignIn.RequireConfirmedAccount = true;

    options.Password.RequiredLength = 6;
    options.Password.RequiredUniqueChars = 2;
    options.Password.RequireNonAlphanumeric = false;

    options.User.RequireUniqueEmail = true;
})
    .AddRoles<IdentityRole>()
    .AddEntityFrameworkStores<ApplicationDbContext>();

services.AddIdentityServer()
    .AddApiAuthorization<ApplicationUser, ApplicationDbContext>();

services.AddAuthentication()
    .AddIdentityServerJwt();
// Startup.Configure()

app.UseIdentityServer();
app.UseAuthentication();
app.UseAuthorization();
// RolesController.Get()

var userid = HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier);
var currentUser = await userManager.FindByIdAsync(userid);
return await userManager.IsInRoleAsync(currentUser, "admin"); // Returns True

Client.csproj

// Program.Main()

builder.Services.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>().CreateClient("WebAppIdentity.ServerAPI"));

builder.Services.AddApiAuthorization();
// Test.razor

<AuthorizeView Roles="admin">
    <Authorizing>
        Authorizing...
    </Authorizing>
    <NotAuthorized>
        You are not an admin. // Always here
    </NotAuthorized>
    <Authorized>
        Hello, admin!
    </Authorized>
</AuthorizeView>

<button @onclick="ShowInfo">Show Info</button>
<p>@infoString</p>

@code
{
    [CascadingParameter]
    private Task<AuthenticationState> stateTask { get; set; }
    private string infoString { get; set; }

    private async void ShowInfo()
    {
        var user = (await stateTask).User;

        infoString = $"Is admin: {user.IsInRole("admin")}"; // Always False
    }
}

person Community    schedule 12.11.2020    source источник
comment
Вы пробовали шаги, описанные в этой проблеме? github.com/dotnet/AspNetCore.Docs/issues/17649   -  person DCCoder    schedule 12.11.2020
comment
@DCCoder Работает !!! Спасибо!   -  person    schedule 12.11.2020


Ответы (1)


В настоящее время существует два приемлемых способа решения этой проблемы.

Первый

# 1 Настройте удостоверение для использования ролей, вызвав AddRoles

services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddRoles<IdentityRole>()
    .AddEntityFrameworkStores<ApplicationDbContext>();

# 2 Настройте сервер идентификации, чтобы поместить утверждение роли в токен идентификатора и токен доступа и предотвратить сопоставление ролей по умолчанию в JwtSecurityTokenHandler.

services.AddIdentityServer()
    .AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options => {
        options.IdentityResources["openid"].UserClaims.Add("role");
        options.ApiResources.Single().UserClaims.Add("role");
    });

// Need to do this as it maps "role" to ClaimTypes.Role and causes issues
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("role");

# 3 В вашем приложении Blazor используйте [Authorize (Roles = admin)] или любую другую роль, которую определяет ваше приложение.

# 4 В API защищенных ресурсов используйте [Authorize (Roles = admin)] или любую другую роль, которую определяет ваше приложение.

Второй

# 1 Добавить класс для настройки параметров. UserOptions.RoleClaim на клиенте

using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Microsoft.Extensions.Options;

namespace App.Client.Services
{
    public class ApiAuthorizationOptionsConfiguration
        : IPostConfigureOptions<RemoteAuthenticationOptions<ApiAuthorizationProviderOptions>>
    {
        public void Configure(RemoteAuthenticationOptions<ApiAuthorizationProviderOptions> options)
        {
            options.UserOptions.RoleClaim ??= "role";
        }

        public void PostConfigure(string name, RemoteAuthenticationOptions<ApiAuthorizationProviderOptions> options)
        {
            if (string.Equals(name, Options.DefaultName))
            {
                Configure(options);
            }
        }
    }
}

# 2 Измените файл Program.cs, чтобы вызвать ApiAuthorizationOptionsConfiguration и настроить утверждение роли.

using App.Client.Services;
...

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

            builder.Services.AddAuthorizationCore();
            builder.Services.AddApiAuthorization();
            builder.Services.TryAddEnumerable(
                ServiceDescriptor.Singleton<
                    IPostConfigureOptions<RemoteAuthenticationOptions<ApiAuthorizationProviderOptions>>,
                    ApiAuthorizationOptionsConfiguration>());

            ...
        }
    }
}
person DCCoder    schedule 12.11.2020
comment
Спасибо. Это действительно должно быть в шаблоне Blazor, поскольку без него роли не работают. - person Christian Rios; 04.03.2021