Blazor wasm 中的政策基础授权

Policy base authoriraztion in blazor wasm

我正在尝试使用数据库中的角色实施基于策略的授权。

服务器端:

services.AddAuthorizationCore(config =>
{
    var context = services
        .BuildServiceProvider()
        .GetService<DbContext>();

    var policies = context.ApplicationPolicies
        .Include(x => x.PolicyRoles)
        .ThenInclude(x => x.Role)
        .ToList();

    foreach (var policy in policies)
    {
        config.AddPolicy(policy.Name, policyBuilder =>
        {
            policyBuilder.RequireRole(policy.PolicyRoles.Select(x => x.Role.Name));
        });
    }
});

客户端:

public class Program
{
    public static async Task Main(string[] args)
    {
        var builder = WebAssemblyHostBuilder.CreateDefault(args);
        builder.RootComponents.Add<App>("app");

        builder.Services.AddHttpClient("MyApp.ServerAPI",
            client => client.BaseAddress = new
            Uri(builder.HostEnvironment.BaseAddress)) 
            .AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();

        builder.Services.AddTransient(sp => 
            sp.GetRequiredService<IHttpClientFactory>()
            .CreateClient("MyApp.ServerAPI"));

        builder.Services.AddScoped<Radzen.NotificationService>();

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


        builder.Services.AddAuthorizationCore(config =>
        {
            var httpClient = builder
                .Services.BuildServiceProvider()
                .GetService<HttpClient>();

            var policies =  await httpClient
                .GetFromJsonAsync<List<ApplicationPolicies>>  
                ("ApplicationPolicies");

            foreach (var policy in policies)
            {
                config.AddPolicy(policy.Name, policyBuilder =>
                {
                    policyBuilder.RequireRole(
                        policy.PolicyRoles.Select(x => x.Role.Name)
                    );
                });
            }
        });

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

此处服务器端代码工作正常,但客户端抛出 AccessTokenNotAvailableException:

我是不是漏掉了什么。

您的问题在这里:

            builder.Services.AddHttpClient("MyApp.ServerAPI",
                        client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress))
                        .AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();

            // each HttpClient use the BaseAddressAuthorizationMessageHandle
            builder.Services.AddTransient(sp => sp.GetRequiredService<IHttpClientFactory>()
                                                    .CreateClient("MyApp.ServerAPI"));

每个 HttpClient 使用 BaseAddressAuthorizationMessageHandler,但当您在此处请求策略时,用户尚未通过身份验证:

            builder.Services.AddAuthorizationCore(config =>
            {
                var httpClient = builder.Services.BuildServiceProvider().GetService<HttpClient>();
                var policies =  await httpClient.GetFromJsonAsync<List<ApplicationPolicies>>("ApplicationPolicies");
                foreach (var policy in policies)
                        {
                            config.AddPolicy(policy.Name, policyBuilder =>
                            {
                                policyBuilder.RequireRole(policy.PolicyRoles.Select(x => x.Role.Name));
                            });
                        }
            });

改为使用不同的 HttpClient:

            builder.Services.AddAuthorizationCore(config =>
            {
                var httpClient = new HttpClient
                {
                    BaseAddress = new Uri(builder.HostEnvironment.BaseAddress)   
                };
                var policies =  await httpClient.GetFromJsonAsync<List<ApplicationPolicies>>("ApplicationPolicies");
                foreach (var policy in policies)
                        {
                            config.AddPolicy(policy.Name, policyBuilder =>
                            {
                                policyBuilder.RequireRole(policy.PolicyRoles.Select(x => x.Role.Name));
                            });
                        }
            });