首页 > 解决方案 > 使用 IIS 自定义 HTTP 模块的 .Net 反向代理的 Windows 身份验证问题

问题描述

我们在 IIS 中使用自定义 HTTP 模块作为 Web 应用程序的反向代理。一般来说,这很好用并且已经做了一段时间,但我们遇到了 Windows 身份验证 (WA) 的问题。我们使用的是 IE 11、IIS 10 和 Server 2016。

当直接访问目标站点时,WA 工作正常——当请求初始 HTML 页面并且后续请求(CSS、JS 等)正常执行时,我们会得到一个浏览器登录对话框。

当通过我们的代理访问时,初始 html 页面会发生相同(正确的行为),第一个 CSS/JS 请求也可以通过身份验证,但随后的请求会导致浏览器登录弹出。

“坏”请求(即导致登录对话框的请求)似乎发生了什么是:

1) 浏览器决定它需要进行身份验证,因此发送一个授权标头(协商,带有 NTLM 令牌)

2) 服务器使用 WWW-Authenticate 响应 (401):使用完整的 NTLM 令牌协商响应

3) 带有授权标头的浏览器重新请求(协商,带有完整的 NTLM 令牌)

4) 服务器以 WWW-Authenticate: Negotiate (with no token) 响应 (401),这会导致浏览器显示登录对话框

5) 输入登录凭据后,浏览器发送与 (1) 相同的请求 - 相同的 NTLM 令牌,服务器响应如 (2),浏览器重新请求如 (3),但这次成功了!

我们已经建立了一个带有一个 html 页面的测试网站,请求 3 个 JS 和 2 个 CSS 文件来复制它。在我们的测试服务器上,我们有两个站点,一个使用我们的反向代理,一个使用 ARR。ARR 网站运行良好。此外,由于上述步骤 (5) 有效,我们认为代理传递从根本上是有效的,即 NTLM 令牌没有被不可靠的编码等弄乱。

确实有效的一件事是,如果我们使用 Fiddler 并在每个请求上放置断点,我们就能够阻止 5 个子请求(JS 和 CSS 文件),一次让一个通过。如果我们让每个序列(即每个 URL/文件的 NTLM 令牌交换,直到 200 响应),那么它就可以工作。这让我们认为我们的代理中存在一些交错效应(例如共享内存损坏),这仍然是一种可能性。

因此,我们将代码放在 BeginRequest 的开头和 EndRequest 的结尾,其中包含一个 Synclock 和一个共享 var 来存储路径 (AppRelativeCurrentExecutionFilePath)。这是为了我们的代码对这些请求/交换中的每一个“单线程”。这符合我们的预期,即只允许进行一次身份验证交换,并在允许下一次之前产生 200。但是,我们仍然遇到服务器拒绝第一次交换的相同问题。那么,这是否表明在 BeginRequest 中/之前发生了一些事情,如果我们将请求保留在 Fiddler 中,那么它们会起作用,但如果我们在 http 模块中执行它则不会?

或者是否存在某种时间问题,即 Fiddler 中的手动断点也意味着我们以“人类”的速度进行操作,从而让事情变得更好?

我们可以看到的一个区别是“连接:保持活动”。该标头在从浏览器到我们的代理站点的请求中,但没有从我们的代理传递到基本站点,但 ARR 站点确实通过了它……这一切都使用 HTTP 1.1。所以我们找不到在我们发出的请求上设置 Keep-Alive 的方法——可能是这样吗?

关于“要尝试的事情”,我们认为我们已经通过让 ARR 站点正常工作并为该站点设置相同的 IE 设置来消除诸如将站点置于 IE 的 Intranet 区域之类的事情。显然,有些地方不对劲,所以我们可能在这里遗漏了一些东西!

简而言之,我们已经为此工作了好几天,并且已经尝试了我们在 SO 和其他地方可以找到的大部分内容,但无法弄清楚到底发生了什么。

任何建议 - 如果您想了解更多信息,请告诉我。我们将非常感激所有帮助!

标签: authenticationiisreverse-proxyntlmkeep-alive

解决方案


推荐阅读