使用 DefaultAzureCredential 和 HttpClient 的 Azure Function 到 Azure Function 请求

Ene*_*Boy 3 c# httpclient azure-functions azure-managed-identity

我需要从另一个 Azure 函数调用 Http Azure 函数。

目前,我调用 Azure Key Vault 来获取目标函数的密钥,并将其放入此处记录的 URL 中:https: //learn.microsoft.com/en-us/azure/azure-functions/functions-bindings- http-webhook-trigger?tabs=csharp#api-key-authorization

但是,我想开始使用托管身份和 DefaultAzureCredential,但我无法找到如何将 DefaultAzureCredential 与 HttpClient 或类似工具一起使用。

如何使用 DefaultAzureCredential 和 HttpClient 从另一个函数调用一个函数?

Rod*_*ave 9

解决这个问题的简单方法是这样的:

var targetFunctionAppAppRegistrationApplicationId = "A Guid that you must get from your target Function's Authentication configuration - 'App (client) ID'";
var url = "https://yourfunctionappname.azurewebsites.net/api/targetfunctionname";
var creds = new DefaultAzureCredential();
var token = await creds.GetTokenAsync(new Azure.Core.TokenRequestContext(new[] { targetFunctionAppAppRegistrationApplicationId }));
using (HttpClient client = new HttpClient())
{
  client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token.Token);
  var result = await client.GetAsync(url);
  // Anything else you want to do with the result
}
Run Code Online (Sandbox Code Playgroud)

上述内容归功于https://spblog.net/post/2021/09/28/call-azure-ad-secured-azure-function-from-logic-app-or-another-function-with-management-identity

然而

上面的代码很快就会导致套接字耗尽。正确的方法是使用 HttpClientFactory,如下所述:https: //learn.microsoft.com/en-us/dotnet/architecture/microservices/implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-要求

由于这些文档中未涵盖此特定用例,因此下面是其外观的示例。

首先,您需要一个消息处理程序:

public class AzureDefaultCredentialsAuthorizationMessageHandler : DelegatingHandler
{
  private readonly TokenRequestContext TokenRequestContext;
  private readonly DefaultAzureCredential Credentials;

  public AzureDefaultCredentialsAuthorizationMessageHandler()
  {
    // This parameter is actually a list of scopes.
    // If your target Function has defined scopes then you should use them here.
    // TokenRequestContext also supports many other options you should probably check out.
    TokenRequestContext = new (new[] { "targetFunctionAppAppRegistrationApplicationId" }); 
    Credentials = new DefaultAzureCredential();
  }

  protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
  {
    var tokenResult = await Credentials.GetTokenAsync(TokenRequestContext, cancellationToken);
    var authorizationHeader = new AuthenticationHeaderValue("Bearer", tokenResult.Token);
    request.Headers.Authorization = authorizationHeader;
    return await base.SendAsync(request, cancellationToken);
  }
}
Run Code Online (Sandbox Code Playgroud)

然后,您需要在依赖注入容器中使用此消息处理程序注册 HttpClient。如果您使用标准 IServiceCollection:

services
  .AddScoped<AzureDefaultCredentialsAuthorizationMessageHandler>()
  .AddHttpClient<YourClassUsingTheHttpClient>((serviceProvider, httpClient) => 
  {
    httpClient.BaseAddress = "https://yourfunctionappname.azurewebsites.net/api/targetfunctionname";
  }).AddHttpMessageHandler<AzureDefaultCredentialsAuthorizationMessageHandler>();
Run Code Online (Sandbox Code Playgroud)

最后,只需有一个YourClassUsingTheHttpClient类,该类在其构造函数中采用 HttpClient:

public class YourClassUsingTheHttpClient
{
  public YourClassUsingTheHttpClient(HttpClient httpClient) { ... }
}
Run Code Online (Sandbox Code Playgroud)

笔记

应该注意的是,上面的代码不处理其他重要问题,例如:

  1. 错误处理
  2. 令牌缓存
  3. 能够为不同的 API 端点使用不同的 HttpClient 和 MessageHandler。

错误处理程序应该可以直接添加。其余的超出了这个问题的范围。

  • 在阅读这个答案时,我感到惊讶的是,不存在与 Microsoft 自己的“HttpClient”的本​​机集成,该集成已经处理包括缓存在内的所有内容。您是否知道在您发布此答案后是否创建了类似的内容? (2认同)