如何使用 Azure AD B2C 保护 Blazor Wasm 应用访问的 Azure 函数?

Posted

技术标签:

【中文标题】如何使用 Azure AD B2C 保护 Blazor Wasm 应用访问的 Azure 函数?【英文标题】:How to secure an Azure Function accessed by a Blazor Wasm app with Azure AD B2C? 【发布时间】:2021-02-28 03:37:15 【问题描述】:

场景:我有一个使用 B2C 身份验证保护的 Blazor wasm 应用程序,它需要调用 HTTP 触发的 Azure 函数。保护该 Azure 函数的最佳方法是什么,以便只有 Blazor 应用和/或经过身份验证的用户才能调用该函数?

到目前为止,我知道如何使用 B2C 保护 Blazor 应用程序(显然很傻!),并且我还能够将 B2C 身份验证添加到 Azure 函数并通过验证 jwt 令牌来保护调用。但我并不清楚这两个部分应该如何结合在一起。

是否应该在 B2C 租户的 Azure Function 的应用注册中公开 API?如果是这样,Blazor 应用将如何对 Azure 函数进行经过身份验证的调用?

或者我是否只是通过 Azure 函数调用的 http 请求标头从 Blazor 应用程序发送 jwt 令牌,然后在函数内手动验证该令牌?

我最近阅读了很多关于这个主题的不同帖子,但我仍然无法弄清楚实现它的最佳解决方案是什么。

任何帮助/提示将不胜感激。

谢谢!

ps:我对使用 Azure API 管理不感兴趣,因为对于一个非常简单的应用解决方案来说,它有点贵。

【问题讨论】:

你有什么更新吗? 嗨@jim-xu !首先,感谢您的详细回答。我昨天才开始尝试让它工作。我一直在为新应用注册与 b2c 门户中的旧应用注册而苦苦挣扎。另外,我不能使用最新版本的 Microsoft.Extensions.Http (5.0) 它似乎破坏了应用程序的其他部分。我会及时向大家发布。 :) 【参考方案1】:

如果要调用Azure AD B2C投影的Azure函数,请参考以下步骤

为 Azure 功能配置 Azure AD B2C

    创建 Azure B2C 应用。

    网络应用程序/API:是

    允许隐式流:是

    在 B2C 应用中设置回复 URL:https://function app url/.auth/login/aad/callback

    在B2C App中设置App ID URL:https://tennat/prefix

    记下 B2C 应用程序的应用程序 ID。

    定义 API 范围。转到 B2C 应用 => 已发布范围

    获取您的 B2C 用户流/策略的元数据 URL。记下此网址。

    可以从运行用户流程页面获取。

    它的格式类似于https://tenant.b2clogin.com/tenant.onmicrosoft.com/v2.0/.well-known/openid-configuration?p=policy

    转到您的功能 => 身份验证/授权

    设置关注

    应用服务身份验证:开启 未通过身份验证时要执行的操作:使用 Azure AD 登录 身份验证提供程序:Azure AAD 管理模式:高级 客户端 ID:步骤 4 中的应用程序 ID 颁发者 URL:来自第 6 步的 URL 允许的受众:来自步骤 3 的应用程序 ID URL

创建客户端应用更多详情请参考here。

在 Azure Function 中配置 CORS 策略

配置应用程序

    创建
     dotnet new blazorwasm -au IndividualB2C --aad-b2c-instance "AAD B2C INSTANCE" --client-id "CLIENT ID" --domain "TENANT DOMAIN" -o APP NAME -ssp "SIGN UP OR SIGN IN POLICY"
    
    代码
创建自定义AuthorizationMessageHandler

    using Microsoft.AspNetCore.Components;
    using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
    
    public class CustomAuthorizationMessageHandler : AuthorizationMessageHandler
    
        public CustomAuthorizationMessageHandler(IAccessTokenProvider provider, 
            NavigationManager navigationManager)
            : base(provider, navigationManager)
        
            ConfigureHandler(
                authorizedUrls: new[]  "<your function app url>" ,
                scopes: new[]  "<the function app  API scope your define>" );
        
    
Program.cs中添加如下代码。
public static async Task Main(string[] args)
        
            var builder = WebAssemblyHostBuilder.CreateDefault(args);
            builder.RootComponents.Add<App>("app");
             // register CustomAuthorizationMessageHandler 
            builder.Services.AddScoped<CustomAuthorizationMessageHandler>();
            // configure httpclient
            // call the following code please add packageMicrosoft.Extensions.Http 3.1.0
            builder.Services.AddHttpClient("ServerAPI", client =>
              client.BaseAddress = new Uri("<your function app url>"))
                    .AddHttpMessageHandler<CustomAuthorizationMessageHandler>();
            // register the httpclient
            builder.Services.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>()
             .CreateClient("ServerAPI"));
            // configure Azure AD auth
            builder.Services.AddMsalAuthentication(options =>
            
                builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);
                options.ProviderOptions.DefaultAccessTokenScopes.Add("<the function app  API scope your define>");


            );

            await builder.Build().RunAsync();
        
调用 API
 @page "/fetchdata"
        @using Microsoft.AspNetCore.Components.WebAssembly.Authentication
        @inject HttpClient Http

        <h1>Call Azure Function</h1>

         <p>This component demonstrates fetching data from the server.</p>

         <p>Result: @forecasts</p>

          <button class="btn btn-primary" @onclick="CallFun">Call Function</button>

          @code 
              private string forecasts;

              protected async Task CallFun()
              
                forecasts = await Http.GetStringAsync("api/http");
              


           

【讨论】:

如果对你有用,可以accept it as an answer吗? 再次感谢@jim-xu!挣扎了几下,终于成功了。 B2C 门户中的“新的和改进的”应用注册似乎与 Azure 功能不兼容,但这是另一回事。 @FPIMarc 需要详细说明这一点。我正在努力解决同样的问题,但没有意识到新的 B2C 门户可能是罪魁祸首。 这个问题的答案是针对旧的 Azure 门户用户界面,因此说明不再有效,我也无法让它工作。有谁知道现在要执行哪些更新步骤? @FPIMarc 您介意分享您的配置(Azure 和 c# 代码)以使其正常工作吗?我一直在试图让我的受 B2C 保护的 Blazor WASM 应用程序成功地对受保护的 B2C Azure 函数进行身份验证。任何援助将不胜感激。我确实为此提出了一个单独的问题,但是在前进方面没有取得太大成功 - ***.com/questions/70549244/…

以上是关于如何使用 Azure AD B2C 保护 Blazor Wasm 应用访问的 Azure 函数?的主要内容,如果未能解决你的问题,请参考以下文章

在 Postman 中为受 Azure AD B2C 保护的 Azure Function App 请求访问令牌

Azure AD B2C FedRAMP是否获得授权?

在 Azure AD B2C 中请求令牌时缺少范围“scp”

Azure AD B2C中的Web API链(On-Behalf-Of)

如何从Azure AD B2C获取用户组信息

如何在 Azure AD B2C 中管理用户流之间的单个帐户/会话