如何使用 Azure AD B2C 保护 Blazor Wasm 应用程序访问的 Azure Functions?
How to secure an Azure Function accessed by a Blazor Wasm app with Azure AD B2C?
场景:我有一个使用 B2C 身份验证保护的 Blazor wasm 应用程序,它需要调用 HTTP 触发的 Azure 函数。保护该 Azure 函数的最佳方法是什么,以便只有 Blazor 应用 and/or 经过身份验证的用户才能调用该函数?
到目前为止,我知道如何使用 B2C 保护 Blazor 应用程序(显然很愚蠢!)并且我还能够将 B2C 身份验证添加到 Azure 函数并通过验证 jwt 令牌来保护调用。但我不清楚这两个部分应该如何结合在一起。
我应该在 B2C 租户的 Azure 函数的应用程序注册中公开一个 API 吗?如果是这样,Blazor 应用如何对 Azure 函数进行经过身份验证的调用?
或者我只是通过 Azure 函数调用的 http 请求 headers 从 Blazor 应用程序发送 jwt 令牌,然后在函数内手动验证该令牌?
我最近阅读了很多关于这个主题的不同帖子,但我仍然无法弄清楚实现它的最佳解决方案是什么。
任何help/cues将不胜感激。
谢谢!
ps:我对使用 Azure API 管理不感兴趣,因为它对于一个非常简单的应用程序解决方案来说有点贵。
如果要调用Azure AD B2C投射的Azure功能,请参考以下步骤
为 Azure 函数配置 Azure AD B2C
创建 Azure B2C 应用。
网络App/API:是
允许隐式流:是
在 B2C 应用程序中设置回复 URL:https://{function app url}/.auth/login/aad/callback
在 B2C 应用程序中设置应用程序 ID URL : https://{tennat}/{prefix}
记下 B2C 应用程序 ID。
定义 API 范围。转到 B2C 应用程序 => 已发布的范围。
获取您的 B2C 用户 flows/policy 的元数据 URL。记下这个 URL.
可从运行用户流页面获取。
格式如https://{tenant}.b2clogin.com/{tenant}.onmicrosoft.com/v2.0/.well-known/openid-configuration?p={policy}
.
转到您的功能=> 身份验证/授权.
设置以下
- 应用服务身份验证:开启
- 未通过身份验证时采取的操作:使用 Azure AD 登录
- 身份验证提供程序:Azure AAD
- 管理模式:高级
- 客户端 ID:{第 4 步中的应用程序 ID}
- 发行人URL:{URL 来自第 6 步}
- 允许的受众:{第 3 步中的应用程序 ID URL}
创建客户端应用程序 详情请参考here.
在 Azure 函数中配置 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
class
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");
}
}
场景:我有一个使用 B2C 身份验证保护的 Blazor wasm 应用程序,它需要调用 HTTP 触发的 Azure 函数。保护该 Azure 函数的最佳方法是什么,以便只有 Blazor 应用 and/or 经过身份验证的用户才能调用该函数?
到目前为止,我知道如何使用 B2C 保护 Blazor 应用程序(显然很愚蠢!)并且我还能够将 B2C 身份验证添加到 Azure 函数并通过验证 jwt 令牌来保护调用。但我不清楚这两个部分应该如何结合在一起。
我应该在 B2C 租户的 Azure 函数的应用程序注册中公开一个 API 吗?如果是这样,Blazor 应用如何对 Azure 函数进行经过身份验证的调用?
或者我只是通过 Azure 函数调用的 http 请求 headers 从 Blazor 应用程序发送 jwt 令牌,然后在函数内手动验证该令牌?
我最近阅读了很多关于这个主题的不同帖子,但我仍然无法弄清楚实现它的最佳解决方案是什么。
任何help/cues将不胜感激。
谢谢!
ps:我对使用 Azure API 管理不感兴趣,因为它对于一个非常简单的应用程序解决方案来说有点贵。
如果要调用Azure AD B2C投射的Azure功能,请参考以下步骤
为 Azure 函数配置 Azure AD B2C
创建 Azure B2C 应用。
网络App/API:是
允许隐式流:是
在 B2C 应用程序中设置回复 URL:
https://{function app url}/.auth/login/aad/callback
在 B2C 应用程序中设置应用程序 ID URL :
https://{tennat}/{prefix}
记下 B2C 应用程序 ID。
定义 API 范围。转到 B2C 应用程序 => 已发布的范围。
获取您的 B2C 用户 flows/policy 的元数据 URL。记下这个 URL.
可从运行用户流页面获取。
格式如
https://{tenant}.b2clogin.com/{tenant}.onmicrosoft.com/v2.0/.well-known/openid-configuration?p={policy}
.转到您的功能=> 身份验证/授权.
设置以下
- 应用服务身份验证:开启
- 未通过身份验证时采取的操作:使用 Azure AD 登录
- 身份验证提供程序:Azure AAD
- 管理模式:高级
- 客户端 ID:{第 4 步中的应用程序 ID}
- 发行人URL:{URL 来自第 6 步}
- 允许的受众:{第 3 步中的应用程序 ID URL}
创建客户端应用程序 详情请参考here.
在 Azure 函数中配置 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
class
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");
}
}