Blazor 级联 AuthorizeView 策略不起作用

Ste*_*eve 6 identityserver4 .net-5 matblazor blazor-webassembly

我正在开发一个新项目,该项目将使用 Identity Server 4 对用户可以和不能访问/查看的内容制定一些深入的策略。

我尝试将 AuthorizeView 与策略一起使用来隐藏导航中的选项,但视图是级联的,这意味着我有这样的内容:

<MatNavMenu>
<MatNavItem Href="/home" Title="Home"><MatIcon Icon="@MatIconNames.Home"></MatIcon>&nbsp; Home</MatNavItem>
<MatNavItem Href="/claims" Title="Claims"><MatIcon Icon="@MatIconNames.Vpn_key"></MatIcon>&nbsp; Claims</MatNavItem>
<AuthorizeView Policy="@PolicyNames.IdentitySystemAccess">
    <Authorized>
        <AuthorizeView Policy="@PolicyNames.AccessManagement">
            <Authorized>
                <MatNavSubMenu @bind-Expanded="@_accessSubMenuState">
                    <MatNavSubMenuHeader>
                        <MatNavItem AllowSelection="false">&nbsp; Access Management</MatNavItem>
                    </MatNavSubMenuHeader>
                    <MatNavSubMenuList>
                        <AuthorizeView Policy="@PolicyNames.User">
                            <Authorized>
                                <MatNavItem Href="users" Title="users"><MatIcon Icon="@MatIconNames.People"></MatIcon>&nbsp; Users</MatNavItem>
                            </Authorized>                               
                        </AuthorizeView>
                        <AuthorizeView Policy="@PolicyNames.Role">
                            <Authorized>
                                <MatNavItem Href="roles" Title="roles"><MatIcon Icon="@MatIconNames.Group"></MatIcon>&nbsp; Roles</MatNavItem>
                            </Authorized>
                        </AuthorizeView>
                    </MatNavSubMenuList>
                </MatNavSubMenu>
            </Authorized>
        </AuthorizeView>
    </Authorized>
</AuthorizeView>
Run Code Online (Sandbox Code Playgroud)

我已检查用户登录后是否存在满足定义的策略所需的声明,但由于某种原因,AuthorizeView 不起作用。

我已更新我的 App.Razor 以使用 AuthorizeRouteView。关于为什么会发生这种情况有什么想法吗?

注意:我使用分配给角色的声明,但这些声明是动态的,我无法在我的策略中使用policy.RequireRole(“my-role”),因此使用:

options.AddPolicy(PolicyNames.User, b =>
                {
                    b.RequireAuthenticatedUser();
                    b.RequireClaim(CustomClaimTypes.User, "c", "r", "u", "d");
                });
Run Code Online (Sandbox Code Playgroud)

当我的应用程序运行时,菜单中的任何项目都不会显示,除了不受 AuthorizeView 保护的主页和声明项目。

Ste*_*eve 4

该问题是由于 Blazor 目前不支持读取作为数组发送的声明。

例如用户:[“c”,“r”,“u”,“d”]

无法读取。

要纠正此问题,您需要添加ClaimsPrincipalFactory

例如

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

namespace YourNameSpace
{
    public class ArrayClaimsPrincipalFactory<TAccount> : AccountClaimsPrincipalFactory<TAccount> where TAccount : RemoteUserAccount
    {
        public ArrayClaimsPrincipalFactory(IAccessTokenProviderAccessor accessor)
        : base(accessor)
        { }


        // when a user belongs to multiple roles, IS4 returns a single claim with a serialised array of values
        // this class improves the original factory by deserializing the claims in the correct way
        public async override ValueTask<ClaimsPrincipal> CreateUserAsync(TAccount account, RemoteAuthenticationUserOptions options)
        {
            var user = await base.CreateUserAsync(account, options);

            var claimsIdentity = (ClaimsIdentity)user.Identity;

            if (account != null)
            {
                foreach (var kvp in account.AdditionalProperties)
                {
                    var name = kvp.Key;
                    var value = kvp.Value;
                    if (value != null &&
                        (value is JsonElement element && element.ValueKind == JsonValueKind.Array))
                    {
                        claimsIdentity.RemoveClaim(claimsIdentity.FindFirst(kvp.Key));

                        var claims = element.EnumerateArray()
                            .Select(x => new Claim(kvp.Key, x.ToString()));

                        claimsIdentity.AddClaims(claims);
                    }
                }
            }

            return user;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在您的程序/启动中注册它(取决于您是否使用 .core 托管),如下所示:

builder.Services.AddOidcAuthentication(options =>
        {
            builder.Configuration.Bind("oidc", options.ProviderOptions);
        })
        .AddAccountClaimsPrincipalFactory<ArrayClaimsPrincipalFactory<RemoteUserAccount>>();
Run Code Online (Sandbox Code Playgroud)

  • 谢谢你。我发现很难在 Blazor WASM 和 .Net 6 上托管的服务器之间操作角色。只需添加上述内容,包括 options.UserOptions.RoleClaim = "roles"; (2认同)