使用MSXML访问被拒绝

5
我有一个VB6后端用于经典ASP网站。然后,该VB使用MSXML2.XMLHTTP调用同一服务器上的Web服务。这在我们所有的服务器上都可以工作,但有一个例外。如果我将Web服务站点设置为接受匿名登录,则它将起作用,但是如果我强制只使用集成安全性,则MSXML返回访问被拒绝错误。
我正在使用示例这里的代码。
Set objDom = CreateObject("MSXML2.DOMDocument")
Set objXmlHttp = CreateObject("MSXML2.XMLHTTP")

' Load XML
objDom.async = False
objDom.loadXML XmlBody

' Open the webservice
objXmlHttp.Open "POST", AsmxUrl, False

' Create headings
objXmlHttp.setRequestHeader "Content-Type", "text/xml; charset=utf-8"
objXmlHttp.setRequestHeader "SOAPAction", SoapActionUrl

' Send XML command
objXmlHttp.send objDom.xml

编辑: 根据AnthonyWJones的建议,我按照检查清单进行了检查,但仍然无法正常工作。使用Fiddler可以看到一个请求和401响应。身份验证选项卡显示:

No Proxy-Authenticate Header is present.
WWW-Authenticate Header is present: Negotiate
WWW-Authenticate Header is present: NTLM

我注意到了一个奇怪的行为。当我使用远程桌面登录的用户凭据调用网站时,它会正常工作。我得到了协商,挑战,然后是200,它可以正常工作。有什么想法为什么只有在用户通过远程桌面登录时才能正常工作而其他时间不行?


1
破损的客户端正在运行哪个操作系统?目标服务器的主机名是否“简单”(是否包含点)?如果不是,则通过代理脚本(http://msdn.microsoft.com/en-us/library/bb250483(VS.85).aspx)进行Intranet区域分配,因此如果您的客户端应用程序由于某种原因未使用代理,则区域分配将失败,并且您会遇到这样的行为。 - EricLaw
我正在使用Windows Server 2003 R2操作系统。目标服务器的主机名是简单的,不包含任何点。如果我使用浏览器导航到Web服务,则显示为本地内部网区域。在Internet选项->连接->LAN设置中,三个框都没有被选中。也许当该用户未加载Explorer时,它正在尝试使用不同的配置? - Ryan
3个回答

3
可能已经太迟回复Ryan了,但其他人可能会遇到同样的问题,所以我会发帖:我有一个开发者也遇到使用MSXML2.XMLHTTP时出现的相同问题。事实上,我有一些很久以前的样本可以这样做,所以我知道它曾经有效,但现在却不行了......可能是最近引入的错误?我们依赖于WinINET堆栈自动检测本地Intranet,然后堆栈愿意执行Windows集成。该站点在代理绕过列表中,使用默认选项将其置于本地Intranet中。当您浏览到该站点并转到安全设置选项卡时,确实会看到本地Intranet被突出显示,因此看起来工作正常。然而,MSXML2.XMLHTTP仍然不愿执行Windows集成......除非您直接在Sites / Advanced按钮上将该站点添加到Local Intranet中。
因此,我的结论是,在WinINET堆栈中存在某种错误,将自动检测到的本地Intranet站点与直接添加到站点列表中的站点进行区分处理。有趣的是,当浏览该站点时,事情按照期望的方式工作,并且自动使用Windows集成(即使没有直接添加到站点):只有通过MSXML2.XMLHTTP进行编程访问才无法正常工作。
最后,这不是我们最终采取的做法:我们改用了MSXML2.ServerXMLHTTP.6.0。该堆栈(WinHTTP)似乎做得很好,但是有一个警告:它默认情况下不使用IE的代理设置,因此您有一些选择-使用ProxyCfg(适用于XP及更早版本),或者对于Vista及更高版本,请使用NETSHWinHTTP堆栈中导入IE代理设置。缺点是每个客户端机器都需要额外配置(这是一个fat client VB应用程序)。我们选择的替代方法是在发送之前执行以下操作:
HTTP.SetProxy 2, "myproxy.mydomain.com", "*.mydomain.com"

因为你将要访问一个mydomain网站,你可能会认为可以使用HTTP.SetProxy 0来绕过代理,但这并不起作用。必须告诉堆栈:“我有一个代理,但是在我的域名下绕过它,并且顺便说一下,我要访问的网站就在这个域名下,也就是本地内部网。”


感谢您的回复。如果可能的话,我仍然希望最终不再使用基本身份验证。 - Ryan

3
我猜您的应用程序依赖底层的WinINET HTTP堆栈,在使用Windows集成安全性时,服务器向客户端发出挑战时,WinINET会将当前用户的凭据呈现给服务器。默认情况下,只有当WinINET认为主机服务器在Intranet区域中时,它才会执行此操作。即使如此,用户的Intranet区域安全设置也可能已被调整为禁止此操作。
请尝试在客户端机器上以与VB6应用程序运行相同的用户身份登录后,使用浏览器访问该站点。它认为服务器所在的区域是什么?如果不是Intranet,则需要将主机添加到该区域的站点列表中。在那里打开区域安全设置,并向下滚动到“用户身份验证”类别。登录应配置为“仅在Intranet区域中自动登录”。 编辑:从您的评论来看,这些设置已正确配置。我想要检查的仅有几件事情是:
  1. 检查服务器的配置是否严格设置为仅接受Windows集成安全。
  2. 检查机器上的代理设置,权限被拒绝是代理服务器的问题吗?
  3. 使用ProgID“MSXML2.XMLHTTP.3.0”确保使用正确版本的MSXML dll(某些其他第三方应用程序的安装可能会损坏注册表,导致使用旧版MSXML)。
  4. 在机器上安装Fiddler并在VB6应用程序尝试调用时监视http对话。是否只有一个401响应?WinINET没有使用用户凭据吗?是否有3个401响应?WinINET已尝试使用当前用户的凭据,但这些凭据不被服务器接受。

现在,我们进入了系统管理员的领域。例如,如果fiddler跟踪显示尝试进行身份验证的对象未使用NTLM,则使用Kerberos身份验证,请检查服务器和客户端的时钟是否相差不超过5分钟,以及域控制器。

检查服务器的事件日志,服务器是否无法联系域控制器。

在服务器上放置一个仅使用Windows集成安全性的简单.htm文件,并尝试从浏览器访问,是否成功?


Web服务既在本地Intranet区域中,又配置为“仅在Intranet区域中自动登录”。还有其他想法吗? - Ryan
谢谢您的回复。我已经更新了我的问题,包括从您的测试中得出的结果。如果我直接浏览 Web 服务,它可以正常工作,但当我从 VB DLL 调用它时就会出现问题。 - Ryan

0

在查看了AnthonyWJones建议的所有内容后,我发现可以通过以下方式使用基本身份验证:

 objXmlHttp.Open "POST", AsmxUrl, False, UserName, Password

如果我允许集成安全性,它会尝试协商但最终失败并返回401错误,但如果只允许基本身份验证,则可以连接。这不是我的首选,但比允许匿名访问更好的解决方法。我将保持开放状态一段时间,以防有人能够解释如何使集成安全性工作,但然后给AnthonyWJones接受的答案,因为他的清单很好,并引导我找到了这个其他选项。
Fiddler在发现所有这些方面非常有帮助。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接