对 NUnit 测试使用 RunImpersonated 进行 HttpClient 调用失败,但在控制台中有效
Posted
技术标签:
【中文标题】对 NUnit 测试使用 RunImpersonated 进行 HttpClient 调用失败,但在控制台中有效【英文标题】:Using RunImpersonated for an HttpClient call fails for a NUnit test, but works in Console 【发布时间】:2020-11-18 23:02:08 【问题描述】:我需要让我的测试作为测试帐户运行。为此,我设置了以下代码以在我的测试帐户中创建一个句柄:
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 :这通常是主机名解析期间的临时错误,意味着本地服务器没有收到来自权威服务器的响应。
它说这通常是一个临时错误,但每次我在 NUnit 测试中模拟运行时都会发生这种情况,而在控制台中运行时则不会。如果我没有模拟运行,当我在 NUnit 测试中运行时,它也永远不会发生。 (简而言之,它只发生在 NUnit 测试和模拟中。)
我不确定如何进行调试。很明显 NUnit 不喜欢我的模仿,但我不知道该怎么办。
如何在 NUnit 测试中使用 RunImpersonated
时成功调用 HttpClient.GetAsync
?
注意:完整的复制代码可以在这里找到:https://github.com/nunit/nunit/issues/3672
【问题讨论】:
如果您以测试用户身份登录并打开浏览器,您可以成功访问该网址还是出现错误?以测试用户身份在 accounts.google.com 上运行 nslookup 怎么样?我只是想确认你的网络配置没有问题 @kylejrp - 以测试用户身份登录时,我可以正常访问 URL。此外,它在未在 NUnit 测试中运行时运行良好(但仍以测试用户身份在代码中运行)。 这可能与您声明httpClient
的上下文有关吗?看起来您声明它超出了RunImpersonated
的范围,我想知道这是否会影响HttpClient
使用的用户。这是在黑暗中拍摄,但如果您在模拟范围内声明 httpClient
会怎样?
@kylejrp - 听起来很有希望,但我刚刚尝试过,但仍然失败。
@kylejrp - 我在 NUnit GitHub 网站上发布了这个:github.com/nunit/nunit/issues/3672 如果你有兴趣,我在那里发布了一个完整的复制品。
【参考方案1】:
这似乎是 .NET Core 的一个错误。在此处查看未解决的问题和讨论:https://github.com/dotnet/runtime/issues/29935
与 .NET Framework 相比,WindowsIdentity.RunImpersonated() 在 .NET Core 中的工作方式似乎有所不同。这会导致各种问题,包括影响 ASP.NET Core 的问题 #29351。
在模拟令牌上设置身份令牌权限的方式有所不同。这会以多种方式导致“拒绝访问”问题。
解决方法
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 的影响是什么,因此使用该解决方法需要您自担风险。
【讨论】:
感谢您的回答!我接受这个作为答案,但我会补充(对于未来的读者)这个设置在 .Net 5.0 中被删除了。因此,此解决方法仅适用于 .Net Core。以上是关于对 NUnit 测试使用 RunImpersonated 进行 HttpClient 调用失败,但在控制台中有效的主要内容,如果未能解决你的问题,请参考以下文章