托管 ASP.NET-Core-Blazor-WebAssembly-App 中基于角色的授权

Role based authorization in hosted ASP.NET-Core-Blazor-WebAssembly-App

我尝试在我的 Blazor 项目中使用角色。我或多或少以这个 https://code-maze.com/using-roles-in-blazor-webassembly-hosted-applications/ 教程

为自己定位

我在数据库中创建了角色,并且一切正常,例如登录等。我加了

services.AddIdentityServer().AddApiAuthorization<ApplicationUser, ApplicationDBContext>(opt =>
        {
            opt.IdentityResources["openid"].UserClaims.Add("role");
            opt.ApiResources.Single().UserClaims.Add("role");
        });
        JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("role");

在 Startup.cs 文件中。为我的用户创建一个“角色”声明,但是当我登录时我没有看到角色声明。

s_hash: nz4meiUsDlXBa8pOfipRmw
sid: 792E67E7F29DF24F13045EECD0DCC6C2
sub: e999a53a-8c76-4737-a202-dabe9e9eeceb
auth_time: 1628245115
idp: local
amr: ["pwd"]
preferred_username: waiter2000@gmx.de
name: waiter2000@gmx.de

问题是我几个小时都无法使用基于角色的授权,因为不知何故我的应用程序没有按应有的方式创建声明字段。

@HenriquePombo 我以为角色会通过登录自动分配。通常我有一个登录名,通过在 Register.cshtml.cs.

中注册分配给一个角色
string UserRole = Request.Form["RoleSelect"];
var user = new ApplicationUser { UserName = Input.Email, Email = Input.Email };
var result_CreateAsync = await _userManager.CreateAsync(user, Input.Password);
var result_AddToRolesAsync = await _userManager.AddToRolesAsync(user, new[] { UserRole });
   

@HenriquePombo

我添加了 class 就像在教程中解释的那样

public class CustomUserFactory : AccountClaimsPrincipalFactory<RemoteUserAccount>
{
    public CustomUserFactory(IAccessTokenProviderAccessor accessor)
        : base(accessor)
    {
    }
    public async override ValueTask<ClaimsPrincipal> CreateUserAsync(
        RemoteUserAccount account,
        RemoteAuthenticationUserOptions options)
    {
        var user = await base.CreateUserAsync(account, options);
        var claimsIdentity = (ClaimsIdentity)user.Identity;
        if (account != null)
        {
            MapArrayClaimsToMultipleSeparateClaims(account, claimsIdentity);
        }
        return user;
    }
    private void MapArrayClaimsToMultipleSeparateClaims(RemoteUserAccount account, ClaimsIdentity claimsIdentity)
    {
        foreach (var prop in account.AdditionalProperties)
        {
            var key = prop.Key;
            var value = prop.Value;
            if (value != null &&
                (value is JsonElement element && element.ValueKind == JsonValueKind.Array))
            {
                claimsIdentity.RemoveClaim(claimsIdentity.FindFirst(prop.Key));
                var claims = element.EnumerateArray()
                    .Select(x => new Claim(prop.Key, x.ToString()));
                claimsIdentity.AddClaims(claims);
            }
        }
    }
}

然后我将服务添加到客户端 Program.cs

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

请记住我使用的是 Blazor Server,所以有些事情可能会有所不同(尤其是在启动时,我会说)。还有一些具体的事情你可以改变你正在使用的例子(例如我正在使用 SessionStorage 等)

另外,我关注了这个 Blazor 教程播放列表 Blazor Tutorial 以帮助我完成这些事情。最好的问候。

Startup.cs

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
      ...
      //Allow the use of Authentication and Authorization in my program
      app.UseAuthentication();
      app.UseAuthorization();
}
public void ConfigureServices(IServiceCollection services)
{
      ...
      //Service I added for handling authentication related stuff
      services.AddScoped<AuthenticationStateProvider, CustomAuthenticationStateProvider>();
}

Class CustomAuthenticationStateProvider

public async Task MarkUserAsAuthenticated(UserModel user)
{
    var identity = new ClaimsIdentity(new[]
    {
        new Claim(ClaimTypes.Name, user.FirstName + " " + user.LastName),
        new Claim(ClaimTypes.Email, user.EmailAddress),
        new Claim(Claims.UserCredentials, user.UserCredentials),
    }, "apiauth_type");

    var roles = await GetUserRoles(user.UserCredentials);
    foreach(var role in roles)
    {
        identity.AddClaim(new Claim(ClaimTypes.Role, role.Name));
    }

    var user1 = new ClaimsPrincipal(identity);

    NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(user1)));

    foreach (var claim in identity.Claims)
    {
        await _sessionStorageService.SetItemAsStringAsync(claim.Type, claim.Value);
    }
}

然后在某个地方:

private readonly AuthenticationStateProvider _customAuthenticationStateProvider;
...
await ((CustomAuthenticationStateProvider)_customAuthenticationStateProvider).MarkUserAsAuthenticated(loginUser);

我自己解决了这个问题。我现在要永远放弃编程,埋葬自己。这是一种耻辱。 Sooo...我在 Register.html.cs 中有“角色”而不是单个“角色”。不同的是:

_userManager.AddToRoleAsync(user, UserRole )

await _userManager.AddToRolesAsync(user, new[] { UserRole });

现在,当我创建一个具有这个小差异的新用户时,一切正常。 谢谢@HenriquePombo 非常感谢您的时间和建议。