使用 Azure 活动目录访问 Azure 函数时,Blazor 客户端出现 CORS 错误
Blazor Client side get CORS error when accessing Azure Function using Azure Active directory
我已经尝试部署我的 Blazor PWA 2 天了,到目前为止没有任何成功,如果有人知道我做错了什么,我将非常感激。
你好
我可以自己解决大部分问题,但我现在遇到了使用 AAD 的 CORS 问题。
这是我的项目设置:
- 在静态网站存储上托管的 Blazor webassembly 客户端(有效
很棒), 净 5
- AzureFunctions 连接到 Azure Sql 服务器数据库(效果很好
在 Blazor 中使用匿名身份验证)
- 我想使用 Azure Active Directory 对用户进行身份验证。
(同时保护 Blazor 应用程序和功能)
所以我创建了一个 App 注册,将我的静态网站地址添加为 SPA uri 并取消选中这两个隐式。
在我的 Blazor 客户端 program.cs 中,我添加了以下代码以连接到 AAD:
builder.Services.AddMsalAuthentication(options =>
{
builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication); //contains clientId, Authority
options.ProviderOptions.DefaultAccessTokenScopes.Add("https://graph.microsoft.com/User.Read");
options.ProviderOptions.LoginMode = "redirect";
});
效果也很好,我可以登录,授权查看按预期工作。
问题是当我尝试使用 «Login with Azure Active Directory» 验证 Azure 功能时,
我尝试了快速配置和高级配置(使用 clientId、tenantId)但是当我
从源 'https://*****9.web.core.windows.net' 访问“https://login.windows.net/tenantid/oauth2/authorize ...(从 'https://myfunctionstorage.azurewebsites.net/api/client/list' 重定向)已被 CORS 策略阻止: 请求的资源上不存在 'Access-Control-Allow-Origin' header。如果不透明的响应满足您的需求,请将请求的模式设置为 'no-cors' 以在禁用 CORS 的情况下获取资源。
我当然在 Azure Functions 配置上为我的 Blazor 客户端地址启用了 CORS,但问题似乎与登录 windows uri...
有关
此外,如果我在应用程序注册中启用令牌 ID 隐式流并在浏览器中访问登录名 url,它就可以正常工作。
到目前为止我能找到的所有示例都是关于 msal 1.0 和使用隐式流而不是 SPA 的应用程序注册的,所以它没有帮助...
感谢您的宝贵时间和帮助。
更新:
从昨天开始我做了更多的研究,我认为它可能与我的 HTTPClient 相关,目前我使用的是基本的(只有一个基本地址)。
但我在一些示例中看到,当使用 AAD 客户端时,它需要更多参数,例如:
builder.Services.AddHttpClient("companiesAPI", cl => { cl.BaseAddress = new Uri("https://localhost:5001/api/"); }) .AddHttpMessageHandler(sp => { var handler = sp.GetService<AuthorizationMessageHandler>() .ConfigureHandler( authorizedUrls: new[] { "https://localhost:5001" }, scopes: new[] { "companyApi" } ); return handler; });
是否需要 AuthorizationMessageHandler?
我还看到一些关于需要使用 «use_impersonation» 范围的参考资料。
使用 msal2/SPA 应用程序注册时是否也需要进行这些更改(在 HttpClient 和 use_impersonation 范围内)?
谢谢
如果想在Blazor webassembly客户端中调用Azure AD投射的Azure函数,请参考以下步骤
如果要在angular应用中调用Azure AD投射的Azure功能,请参考以下代码
创建Azure AD应用保护功能
注册 Azure AD 应用程序。完成后,请复制 应用程序(客户端)ID 和 目录(租户)ID
配置重定向 URI。 Select Web 并输入 <app-url>/.auth/login/aad/callback
.
启用隐式授权流程
定义API范围并复制
创建客户端密钥。
在您的应用服务应用程序中启用 Azure Active Directory
在 Azure 函数中配置 CORS 策略
创建客户端AD应用访问功能
- 注册申请
- 启用隐式授权流程
- 配置API权限。让您的客户端应用程序具有访问功能的权限
代码
- 创建自定义
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");
}
}
我已经尝试部署我的 Blazor PWA 2 天了,到目前为止没有任何成功,如果有人知道我做错了什么,我将非常感激。 你好 我可以自己解决大部分问题,但我现在遇到了使用 AAD 的 CORS 问题。
这是我的项目设置:
- 在静态网站存储上托管的 Blazor webassembly 客户端(有效 很棒), 净 5
- AzureFunctions 连接到 Azure Sql 服务器数据库(效果很好 在 Blazor 中使用匿名身份验证)
- 我想使用 Azure Active Directory 对用户进行身份验证。 (同时保护 Blazor 应用程序和功能)
所以我创建了一个 App 注册,将我的静态网站地址添加为 SPA uri 并取消选中这两个隐式。 在我的 Blazor 客户端 program.cs 中,我添加了以下代码以连接到 AAD:
builder.Services.AddMsalAuthentication(options =>
{
builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication); //contains clientId, Authority
options.ProviderOptions.DefaultAccessTokenScopes.Add("https://graph.microsoft.com/User.Read");
options.ProviderOptions.LoginMode = "redirect";
});
效果也很好,我可以登录,授权查看按预期工作。
问题是当我尝试使用 «Login with Azure Active Directory» 验证 Azure 功能时, 我尝试了快速配置和高级配置(使用 clientId、tenantId)但是当我
从源 'https://*****9.web.core.windows.net' 访问“https://login.windows.net/tenantid/oauth2/authorize ...(从 'https://myfunctionstorage.azurewebsites.net/api/client/list' 重定向)已被 CORS 策略阻止: 请求的资源上不存在 'Access-Control-Allow-Origin' header。如果不透明的响应满足您的需求,请将请求的模式设置为 'no-cors' 以在禁用 CORS 的情况下获取资源。
我当然在 Azure Functions 配置上为我的 Blazor 客户端地址启用了 CORS,但问题似乎与登录 windows uri...
有关此外,如果我在应用程序注册中启用令牌 ID 隐式流并在浏览器中访问登录名 url,它就可以正常工作。
到目前为止我能找到的所有示例都是关于 msal 1.0 和使用隐式流而不是 SPA 的应用程序注册的,所以它没有帮助...
感谢您的宝贵时间和帮助。
更新: 从昨天开始我做了更多的研究,我认为它可能与我的 HTTPClient 相关,目前我使用的是基本的(只有一个基本地址)。
但我在一些示例中看到,当使用 AAD 客户端时,它需要更多参数,例如:
builder.Services.AddHttpClient("companiesAPI", cl => { cl.BaseAddress = new Uri("https://localhost:5001/api/"); }) .AddHttpMessageHandler(sp => { var handler = sp.GetService<AuthorizationMessageHandler>() .ConfigureHandler( authorizedUrls: new[] { "https://localhost:5001" }, scopes: new[] { "companyApi" } ); return handler; });
是否需要 AuthorizationMessageHandler? 我还看到一些关于需要使用 «use_impersonation» 范围的参考资料。
使用 msal2/SPA 应用程序注册时是否也需要进行这些更改(在 HttpClient 和 use_impersonation 范围内)?
谢谢
如果想在Blazor webassembly客户端中调用Azure AD投射的Azure函数,请参考以下步骤 如果要在angular应用中调用Azure AD投射的Azure功能,请参考以下代码
创建Azure AD应用保护功能
注册 Azure AD 应用程序。完成后,请复制 应用程序(客户端)ID 和 目录(租户)ID
配置重定向 URI。 Select Web 并输入
<app-url>/.auth/login/aad/callback
.启用隐式授权流程
定义API范围并复制
创建客户端密钥。
在您的应用服务应用程序中启用 Azure Active Directory
在 Azure 函数中配置 CORS 策略
创建客户端AD应用访问功能
- 注册申请
- 启用隐式授权流程
- 配置API权限。让您的客户端应用程序具有访问功能的权限
代码
- 创建自定义
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");
}
}