Azure active directory 使用Azure Active directory访问Azure函数时Blazor客户端获取CORS错误

Azure active directory 使用Azure Active directory访问Azure函数时Blazor客户端获取CORS错误,azure-active-directory,blazor,blazor-client-side,azure-function-app,Azure Active Directory,Blazor,Blazor Client Side,Azure Function App,我已经尝试部署我的Blazor PWA两天了,到目前为止没有任何成功,如果有人知道我做错了什么,我将非常感激。 你好 我可以自己解决大部分问题,但我现在被困在使用AAD的CORS问题上 以下是我的项目设置: Blazor webassembly客户端托管在静态网站存储(works)上 太好了),净5 AzureFunctions连接到Azure Sql Server数据库(非常有效 在Blazor中使用匿名身份验证) 我要使用Azure Active Directory对用户进行身份验证。 (

我已经尝试部署我的Blazor PWA两天了,到目前为止没有任何成功,如果有人知道我做错了什么,我将非常感激。 你好 我可以自己解决大部分问题,但我现在被困在使用AAD的CORS问题上

以下是我的项目设置:

  • Blazor webassembly客户端托管在静态网站存储(works)上 太好了),净5
  • AzureFunctions连接到Azure Sql Server数据库(非常有效 在Blazor中使用匿名身份验证)
  • 我要使用Azure Active Directory对用户进行身份验证。 (保护blazor应用程序和功能)
因此,我创建了一个应用程序注册,将我的静态网站地址添加为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";
});
这也很好,我可以登录,授权查看工程的预期

问题是当我尝试使用«使用Azure Active Directory登录»验证Azure函数时, 我尝试了express和advanced配置(使用clientId、tenantId),但当我

在'https://login.windows.net/tenantid/oauth2/authorize ... (从'https://myfunctionstorage.azurewebsites.net/api/client/list“)来自源“https://****9.web.core.windows.net”已被CORS策略阻止:请求的资源上不存在“访问控制允许源”标头。如果不透明响应满足您的需要,请将请求的模式设置为“no cors”,以获取禁用cors的资源

我当然在Azure功能配置中为Blazor客户端地址启用了CORS,但问题似乎与登录windows uri有关

此外,如果我在应用程序注册中启用令牌id隐式流,并在浏览器中访问登录url,那么它就可以正常工作

到目前为止,我能找到的所有例子都是关于MSAL1.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; });
builder.Services.AddHttpClient(“companiesAPI”,cl=>{cl.BaseAddress=newURI(“https://localhost:5001/api/AddHttpMessageHandler(sp=>{var handler=sp.GetService().ConfigureHandler(authorizedURL:new[]{https://localhost:5001},作用域:new[]{“companyApi”};返回处理程序;});
需要授权MessageHandler吗? 此外,我还看到一些关于需要使用«use_impersonation»范围的参考资料

在使用msal2/SPA应用程序注册时,是否也需要这些更改(在HttpClient和use_模拟范围上)


谢谢

如果要调用Blazor webassembly客户端中Azure AD投影的Azure函数,请参考以下步骤 如果您想在angular应用程序中调用Azure AD投影的Azure函数,请参考以下代码

  • 创建Azure广告应用程序以保护功能

  • 注册Azure广告应用程序。完成此操作后,请复制应用程序(客户端)ID目录(租户)ID

  • 配置重定向URI。选择Web并键入

  • 创建客户端机密

  • 在应用程序服务应用程序中启用Azure Active Directory

  • 在Azure功能中配置CORS策略

  • 创建客户端广告应用程序以访问功能

  • 注册申请
  • 启用隐式授权流
  • 配置API权限。让您的客户端应用程序具有访问该功能的权限
  • 代码

  • 创建自定义
    AuthorizationMessageHandler
  • 调用API
  • @page”/fetchdata
    @使用Microsoft.AspNetCore.Components.WebAssembly.Authentication
    @注入HttpClient Http
    调用Azure函数
    此组件演示如何从服务器获取数据

    结果:@预测

    调用函数 @代码{ 私人字符串预测; 受保护的异步任务CallFun() { 预测=等待Http.GetStringAsync(“api/Http”); } }

    您是否查看了“应用程序注册”中配置的重定向url?另外,您是否将它们定义为SPA?谢谢您的回答,是的,我的本地主机和部署url都在重定向url中注册,并且它们被定义为SPA。由于我能够从web客户端登录并从浏览器运行函数(登录后),我敢打赌问题在于客户端和函数API之间的通信。@ChristianMeurrens您是否在Azure函数中配置了CORS:?在函数中配置CORS无助于@JimXu。问题的原因是函数试图进行交互式身份验证,这是错误的,因为它是一个API。您需要检查访问令牌是否正确连接,在中检查令牌中的声明是否符合函数的预期。@Juunas我期待类似的内容,我将深入研究,谢谢。请随意转载作为答案,以便我可以验证。如果它对您有用,您可以吗?
    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>" });
        }
    }
    
     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();
            }
    
    @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");
        }
    
    
    }