如何使用来自 IHttpClientFactory 的 HttpClient 将 cookie 添加到请求中

Posted

技术标签:

【中文标题】如何使用来自 IHttpClientFactory 的 HttpClient 将 cookie 添加到请求中【英文标题】:How to add a cookie to a request using HttpClient from IHttpClientFactory 【发布时间】:2020-07-01 14:04:15 【问题描述】:

背景 我正在开发一个 ASP.NET Core Web API,我们在 API 中调用第 3 方 API。这个第 3 方 API 要求每个请求都包含一个带有访问令牌的 cookie。我们的 API 从声明中获取此令牌(来自与请求关联的用户的 ClaimsPrincipal)。

详细信息This answer 展示了如何在请求中设置 cookie,但该示例要求手动构造 HttpClient(以便能够注入 HttpClientHandlerCookieContainer)。而且由于不希望手动实例化 HttpClient,我宁愿通过 DI 注入 HttpClient,this example 说明了这一点(使用 IHttpClientFactory)。

在我的服务中,我可以访问一个注入的HttpClient 实例(_httpClient),最简单的函数如下所示:

public async Task<string> GetStatusAsync(ClaimsPrincipal user)

    // TODO: Add cookie with access token (from user's claims) before making request
    return await _httpClient.GetStringAsync(Endpoints.Status);

This GitHub issue 询问在使用 IHttpClientFactory 时如何包含授权 cookie,答案是 use the header propagation middleware。现在谈谈我的问题:

据我所知,您在应用程序启动时的服务配置期间设置了标头传播中间件(包含所有标头和 cookie 等)。然而,在我们的 API 中,在实际向 3rd 方 API 发出请求之前,我没有身份验证 cookie 的值。

问题 在发出实际请求之前,如何在使用IHttpClientFactory 注入我的服务的HttpClient 实例上的请求中添加cookie?

【问题讨论】:

您可以在设置 HttpClientFactory 时使用 ConfigurePrimaryHttpMessageHandler() 方法来配置主处理程序,这应该允许您使用 Cookie 类使用 HttpClientHandler 配置 cookie。 docs.microsoft.com/en-us/dotnet/api/… 【参考方案1】:

您可以在 AddHeaderPropagation 配置函数中放置一个静态函数:

services.AddHeaderPropagation(options =>
    
        options.Headers.Add(MyCookie());
    );

MyCookie函数内部, 从它们中获取当前上下文结束提取所有需要的数据。

如果您需要当前流程或当前控制器中的某些内容,您可以添加它 在 httpSession 中并将其放入 MyCookie 函数中。

【讨论】:

感谢您的回复。解决方案是使用标头传播,但使用当前上下文(可通过Headers.Add 重载之一获得),如下所示:***.com/a/62696725/310001【参考方案2】:

解决方案确实是使用header propagation。我只需要将所有部分正确地组合在一起即可。

标头传播在ConfigureServices(在Startup.cs)内配置。而且由于我想使用当前用户声明中的数据,所以诀窍是,在添加 cookie 标头时,使用一个重载,该重载接受一个函数,使您可以访问当前上下文:

services.AddHeaderPropagation(options =>

    options.Headers.Add("Cookie", context =>
    
        var accessToken = context.HttpContext.User.Claims.FirstOrDefault(c => c.Type == "access-token")?.Value;
        return accessToken != null ? new StringValues($"token=accessToken") : new StringValues();
    );
);

除此之外,由于我使用的是Typed Service,因此我还必须配置该特定服务应该转发 cookie 标头(在 Startup.cs 中的 ConfigureServices 内的同一位置):

services.AddHttpClient<IApiService, ApiService>(httpClient =>

    httpClient.BaseAddress = new Uri("https://httpbin.org/");
).AddHeaderPropagation(options =>

    options.Headers.Add("Cookie");
);

最后,给我带来了一些麻烦的事情:由于我使用的是当前用户声称的数据,因此注册了标头传播中间件(Configure 中的Configure 中的Startup.cs)必须在添加身份验证中间件 (app.UseAuthentication();) 之后发生。如果没有,则声明尚未设置。

作为最后的提示:在处理此问题时,我会在 https://httpbin.org/ 中领导我们。那里的请求检查端点对于查看您在请求中实际传递的数据非常有用。

【讨论】:

以上是关于如何使用来自 IHttpClientFactory 的 HttpClient 将 cookie 添加到请求中的主要内容,如果未能解决你的问题,请参考以下文章

如何在ASP.NET Core 中使用IHttpClientFactory

如何使用 Moq 从 IHttpClientFactory 模拟 HTTPClient 并结合 .NET Core 中的 Polly 策略

单元测试 | 如何Mock IHttpClientFactory

在 ASP.NET Core 中使用 IHttpClientFactory 发出 HTTP 请求

为IHttpClientFactory添加动态命名配置

如何为每个 url 使用 Polly 和 IHttpClientFactory