使用Active Directory B2C保护Blazor WASM应用程序和Web API

问题描述

我遇到的情况是,我有一个通过AD B2C保护的Blazor WASM(仅限客户端)应用程序。根据我阅读的文档,我已经在AD B2C中注册一个应用程序(例如BlazorApp),并将Blazor应用程序连接到该实例。此Blazor应用程序对.NET Core Web API进行API调用,在此端点上,端点受到安全保护(使用[Authorize]属性)。根据我阅读的文档,我还在AD B2C中注册了Web API(例如WebApi),并连接了该API以连接到该实例。

我遇到的问题是,当我在Blazor应用中进行身份验证,然后通过API调用传递访问/ ID令牌时,Web API无法对该令牌进行身份验证(未经授权的错误响应)。当我将Web API连接到BlazorApp注册时,它就起作用了(我猜是因为这是从那里发出令牌的)。但这似乎与在AD中将每个应用程序/ api注册为单独注册的建议背道而驰。

如何获得WebApi注册以识别BlazorApp发行的令牌?我要解决这个错误吗?我应该只连接Web API与BlazorApp实例进行对话吗?

其他信息:

Blazor WASM(客户端)-Program.cs (已删除敏感信息)

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

            ...

            builder.Services.AddMsalAuthentication(options =>
            {
                builder.Configuration.Bind("AzureAdB2C",options.ProviderOptions.Authentication);
                options.ProviderOptions.DefaultAccesstokenScopes.Add(@"https://<tenant name>.onmicrosoft.com/blazorapp/app.read");
                options.ProviderOptions.DefaultAccesstokenScopes.Add(@"https://<tenant name>.onmicrosoft.com/blazorapp/app.write");
            });

            ...

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

Blazor WASM(客户端)-appsettings.json (已删除敏感信息)

{
    "AzureAdB2C": {
        "Authority": "https://<tenant name>.b2clogin.com/<tenant name>.onmicrosoft.com/B2C_1_SignUpSignIn","ClientId": "<BlazorApp Application ID>","ValidateAuthority": false
    }
}

Web API(.NET Core 3.1)-StartUp.cs (已删除敏感信息)

public void ConfigureServices(IServiceCollection services)
        {
            ...
        services.AddAuthentication(AzureADB2CDefaults.BearerAuthenticationScheme)
                .AddAzureADB2CBearer(options => Configuration.Bind("AzureAdB2C",options));

            services.AddControllers();

            ...

        }

Web API(.NET Core 3.1)-appsettings.json (已删除敏感信息)

注意:当我用BlazorApp应用程序ID替换WebApi应用程序ID时,身份验证有效

{
    "AzureAdB2C": {
        "Instance": "https://<tenant name>.b2clogin.com/tfp/","ClientId": "<WebAPI Application ID>","Domain": "<tenant name>.onmicrosoft.com","SignUpSignInPolicyId": "B2C_1_SignUpSignIn"
    },...
}

解决方法

您的项目未使用OBO流,OBO流需要三个应用程序,特别是一个client-side和两个api-side,请参见here

回到问题所在,首先,您的问题是配置范围错误,因为api-side应用需要公开自己的api,Blazor应用端的API权限可以访问到api-side,因此在api-side上配置了对范围的访问权限,因此我们需要将https://<tenant name>.onmicrosoft.com/webapiapp/app.read放在范围上,您的blazor应用程序仅用于配置访问权限。>

之所以有效,是因为您使用blazor应用程序来请求blazor应用程序自己的api,这是可行的,尽管有些奇怪,但是可以请求自己。

因此对于您的项目,正确的请求应如下所示。

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

            ...

            builder.Services.AddMsalAuthentication(options =>
            {
                builder.Configuration.Bind("AzureAdB2C",options.ProviderOptions.Authentication);
                options.ProviderOptions.DefaultAccessTokenScopes.Add(@"https://<tenant name>.onmicrosoft.com/webapiapp/app.read");
                options.ProviderOptions.DefaultAccessTokenScopes.Add(@"https://<tenant name>.onmicrosoft.com/webapiapp/app.write");
            });

            ...

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

{
    "AzureAdB2C": {
        "Instance": "https://<tenant name>.b2clogin.com/tfp/","ClientId": "<Application ID>","Domain": "<tenant name>.onmicrosoft.com","SignUpSignInPolicyId": "B2C_1_SignUpSignIn"
    },...
}