不强制执行 webassembly blazor 客户端应用程序中的授权视图

Authorization views in webassembly blazor client app are not enforced

我有一个在 webassembly blazor 中开发并受 Azure AD 保护的客户端应用程序,其中已注册并定义了 3 个角色并将其分配给用户。

用户登录后,用户将被重定向到显示声明集的个人资料页面

Claim Type            Value
oid                   091fadf9-b0bd-4583-b55d-XXXX
preferred_username    XX
roles                 ["Administrator"]

根据用户角色不同 UI 将显示,但是这不起作用

<AuthorizeView Roles="Administrator">
   ADMIN UI
</AuthorizeView>

我的程序 class 看起来像这样:

 public static async Task Main(string[] args)
        {
            var builder = WebAssemblyHostBuilder.CreateDefault(args);
            builder.RootComponents.Add<App>("app");
            //builder.Logging.SetMinimumLevel(LogLevel.Debug);


            ////builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
            builder.Services.AddScoped<CustomAuthorizationMessageHandler>();

            builder.Services.AddHttpClient("myAPI",
               client => client.BaseAddress = new Uri("private API URL"))
              .AddHttpMessageHandler<CustomAuthorizationMessageHandler>();

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

           builder.Services.AddMsalAuthentication(options =>
            {
               builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);
                options.ProviderOptions.DefaultAccessTokenScopes.Add(myAPI);
                options.UserOptions.RoleClaim = "roles";
            });

            await builder.Build().RunAsync();
        }

我支持 class 用户:

 public class UserClaimsBase: ComponentBase
    {
        // AuthenticationStateProvider service provides the current user's ClaimsPrincipal data.
        [Inject]
        private AuthenticationStateProvider AuthenticationStateProvider { get; set;
        }
        protected string _authMessage;
        protected IEnumerable<Claim> _claims = Enumerable.Empty<Claim>();

        // Defines list of claim types that will be displayed after successfull sign-in.
        private string[] returnClaims = { "name", "preferred_username", "tid", "oid", "roles" };

        protected override async Task OnInitializedAsync()
        {
            await GetClaimsPrincipalData();
        }

        /// <summary>
        /// Retrieves user claims for the signed-in user.
        /// </summary>
        /// <returns></returns>
        private async Task GetClaimsPrincipalData()
        {
            // Gets an AuthenticationState that describes the current user.
            var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();

            var user = authState.User;

            // Checks if the user has been authenticated.
            if (user.Identity.IsAuthenticated)
            {
                _authMessage = $"{user.Identity.Name} is authenticated.";

                // Sets the claims value in _claims variable.
                // The claims mentioned in returnClaims variable are selected only.
                _claims = user.Claims.Where(x => returnClaims.Contains(x.Type));
            }
            else
            {
                _authMessage = "The user is NOT authenticated.";
            }
        }
    }

这里有什么问题吗? 我不确定我缺少什么? 感谢任何帮助。

问题请参考以下步骤

  1. 在您的 Azure AD 应用程序中定义 appRole

在应用清单中添加以下内容

"appRoles": [
        
        {
            "allowedMemberTypes": [
                "User",
                "Application"
            ],
            "description": "admin",
            "displayName": "Admin",
            "id": "d1c2ade8-98f8-45fd-aa4a-6d06b957c66f",
            "isEnabled": true,
            "lang": null,
            "origin": "Application",
            "value": "admin"
        },
        {
            "allowedMemberTypes": [
                "User",
                "Application"
            ],
            "description": "access database test",
            "displayName": "Test",
            "id": "d1c2ade8-98f8-45fd-aa4a-6d06b947c66f",
            "isEnabled": true,
            "lang": null,
            "origin": "Application",
            "value": "test"
        }
    ],
  1. Assign appRole to user

  2. 配置应用程序

一个。包裹

 <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="3.2.1" />
    <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Build" Version="3.2.1" PrivateAssets="all" />
    <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="3.2.1" PrivateAssets="all" />
    <PackageReference Include="Microsoft.Authentication.WebAssembly.Msal" Version="3.2.1" />
    <PackageReference Include="System.Net.Http.Json" Version="3.2.0" />

b。扩展 RemoteUserAccount 以包含角色的属性

using System;
using System.Text.Json.Serialization;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;

public class CustomUserAccount : RemoteUserAccount
{
    [JsonPropertyName("roles")]
    public string[] Roles { get; set; } = Array.Empty<string>();

}

b。定义自定义用户工厂以转换 appRole 声明

using System;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication.Internal;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Graph;

public class CustomAccountFactory
    : AccountClaimsPrincipalFactory<CustomUserAccount>
{
    private readonly ILogger<CustomAccountFactory> logger;
    private readonly IServiceProvider serviceProvider;

    public CustomAccountFactory(IAccessTokenProviderAccessor accessor,
        IServiceProvider serviceProvider,
        ILogger<CustomAccountFactory> logger)
        : base(accessor)
    {
        this.serviceProvider = serviceProvider;
        this.logger = logger;
    }
    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;

            foreach (var role in account.Roles)
            {
                userIdentity.AddClaim(new Claim("appRole", role));
            }
        }

        return initialUser;
    }
}

c。在 Program.cs

中配置 Azure AD 身份验证
 builder.Services.AddMsalAuthentication<RemoteAuthenticationState,
                 CustomUserAccount>(options =>
                 {
                     builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);
                    
                     options.UserOptions.RoleClaim = "appRole";
                 }).AddAccountClaimsPrincipalFactory<RemoteAuthenticationState, CustomUserAccount,
             CustomAccountFactory>();
  1. 授权
# add the following code in the page according to your need
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize(Roles = "admin")]
  1. 测试

我的页面

@page "/counter"
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize(Roles = "admin")]
<h1>Counter</h1>

<p>Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    private async Task IncrementCount()
    {

        currentCount++;
    }
}

我的用户

结果