使用 RunImpersonated 进行 HttpClient 调用对于 NUnit 测试失败,但在控制台中有效

Using RunImpersonated for an HttpClient call fails for a NUnit test, but works in Console

我需要将我的测试 运行 作为测试帐户。为此,我设置了以下代码来创建我的测试帐户的句柄:

SafeAccessTokenHandle testAccountHandle;

bool returnValue = LogonUser("TestAccount", "myDom.net", 
       "pass", 2, 0, out testAccountHandle);

然后我可以调用加载 URL:

HttpResponseMessage response = null;

await WindowsIdentity.RunImpersonated<Task>(testAccountHandle, async () =>
{
    var url = "https://accounts.google.com/.well-known/openid-configuration";
    response = await httpClient.GetAsync(url);
});
testAccountHandle.Dispose();

当我在控制台应用程序中 运行 时,它工作得很好。 (同样在 LinqPad 中。)

然而,当我在 NUnit 测试中 运行 这段代码时,出现以下错误:

System.Net.Sockets.SocketException : This is usually a temporary error during hostname resolution and means that the local server did not receive a response from an authoritative server.

它说这通常是一个临时错误,但每次我 运行 在 NUnit 测试中模拟时都会发生,而当我在控制台中 运行 时从来没有发生过。当我 运行 在 NUnit 测试中,如果我没有被冒充,它也永远不会发生。 (简而言之,它仅在 NUnit 测试和模拟时发生。)

我不确定如何调试它。很明显 NUnit 不喜欢我的模仿,但我不知道该怎么办。

如何在 NUnit 测试中使用 RunImpersonated 时成功调用 HttpClient.GetAsync

注意:可以在此处找到完整的重现代码:https://github.com/nunit/nunit/issues/3672

这似乎是 .NET Core 的错误。请在此处查看未解决的问题和讨论:https://github.com/dotnet/runtime/issues/29935

It seems that WindowsIdentity.RunImpersonated() works differently in .NET Core compared with .NET Framework. This is causing a variety of issues including one affecting ASP.NET Core, #29351.

There is some difference in the way that the identity token permissions are getting set on the impersonated token. This is causing "access denied" issues in a variety of ways.

解决方法

Issue #29351 from ASP.NET Core 引用了这个确切的错误消息并包含一个解决方法。将环境变量 DOTNET_SYSTEM_NET_HTTP_USESOCKETSHTTPHANDLER 设置为 0 会禁用 SocketsHttpHandler 并使此问题消失。例如,以下工作没有错误:

Environment.SetEnvironmentVariable("DOTNET_SYSTEM_NET_HTTP_USESOCKETSHTTPHANDLER", "0");
HttpResponseMessage response = null;

await WindowsIdentity.RunImpersonated<Task>(testAccountHandle, async () =>
{
    var url = "https://accounts.google.com/.well-known/openid-configuration";
    response = await httpClient.GetAsync(url);
});

您可能需要考虑只为这个特定测试而不是为每个测试设置这个环境变量。我不确定禁用 SocketsHttpHandler 的影响是什么,因此使用变通方法需要您自担风险。