我以前就这个主题发过帖子,但是在处理其他事情一年之后,我又设法再次陷入困境。我将尝试简要概述该场景以及当前使工作正常进行的尝试:
- 在主机上托管 HTML、JS 等的 IIS Web 服务器:iis.mycompany.com(简称foo)
- 通过主机上的 Windows 服务托管的 WCF RESTful Web 服务:wcf.mycompany.com(称为bar)
从foo提供的 Javascript 通过对bar上的 WCF 服务进行 RESTful ajax 调用(GET
或POST
取决于操作)来工作,显然这些是跨域调用,因为它们不在同一主机上。
Javascript 使用 jQuery (1.7.2) 框架来操作 DOM 并执行对bar的ajax 调用,预期的内容类型POSTS
是 is ,并且预期JSON
的响应也是 (application/json)。GETS
JSON
Bar将其 WCF 服务配置TransportCredentialOnly
为安全模式,传输客户端凭据类型为NTLM
,因此只有经过身份验证的用户才能联系服务。
使用 WCF 的扩展将CORS 支持添加到bar 的WCF 服务:
http://blogs.msdn.com/b/carlosfigueira/archive/2012/05/15/implementing-cors-support-in-wcf.aspx
我们添加了额外的标题,并根据大量互联网文章修改了帖子中已经包含的一些标题:
property.Headers.Add("Access-Control-Allow-Headers", "Accept, Content-Type");
property.Headers.Add("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
property.Headers.Add("Access-Control-Max-Age", "172800");
property.Headers.Add("Access-Control-Allow-Origin", "http://iis.mycompany.com");
property.Headers.Add("Access-Control-Allow-Credentials", "true");
property.Headers.Add("Content-type", "application/json");
提供有关启用 CORS 的信息的站点建议Access-Control-Allow-Origin
应将响应标头设置为,"*"
但是在我们的情况下这是不可能的,因为我们使用以下设置进行 jQuery ajax 调用:
$.ajaxSetup({
cache: "false",
crossDomain: true,
xhrFields: {
withCredentials: true
}
});
事实证明,当您在 ajax 调用"*"
中使用时,您不能使用已接受的来源:"withCredentials"
https://developer.mozilla.org/en/http_access_control
“重要提示:在响应凭据请求时,服务器必须指定域,并且不能使用通配符。”
目前在我们的开发实验室中,这并不重要,因为我们可以将请求硬编码到 IIS (foo) 服务器 URL。
现在的主要问题似乎是尝试POST
请求(GET
正在使用上述配置工作)。当浏览器尝试该POST
过程时,它首先向OPTIONS
服务器发送一个标头,请求允许OPTIONS
后续发布。这是我们希望看到我们在 CORS 支持 WCF 扩展中配置的标头被传回的地方,但是我们还没有走得那么远;在响应返回为"401 Unauthorized"之前,我相信这与请求 NTLM 的传输安全绑定配置有关,但我不确定。
此外,我对此不是很有经验,但我没有看到太多关于POST
使用application/json
内容类型的信息,而不是text/plain
执行跨域请求时。
我知道人们可能会建议JSONP
作为一个真正的解决方案,我并不反对不同的方法,实际上我鼓励任何人提出最佳实践,因为这将有助于其他人稍后阅读这个问题。但是,请在提出替代方案之前尝试回答问题。
非常感谢任何做出贡献的人。
彼得斯基 :)
更新:
Chrome (20.xx) 似乎不会遇到不协商 NTLM 以OPTIONS
从服务器检索标头响应的问题,但 Firefox (13.0.1) 会。
我们还注意到有人已经在 Firefox 论坛上发布了一个错误,我们已将信息添加到:
http://bugzilla.mozilla.org/show_bug.cgi?id=751552
请投票支持在 bugzilla 网站上修复此错误!
使用以下代码,我们可以观察网络跟踪以查看 Firefox 失败和 Chrome 工作正常:
var url = "http://myWebServiceServer/InstantMessagingService/chat/message/send";
var data = '{ "remoteUserUri" : "sip:foo.bar@mydomain.com", "message" : "This is my message" }';
var request = new XMLHttpRequest();
request.open("POST", url, true);
request.withCredentials = true;
request.setRequestHeader("Content-Type", "application/json");
request.send(data);
console.log(request);
另外,IE8 不支持XMLHttpRequest
跨域调用,而是支持它自己的神奇XDomainRequest
对象,因此我们需要做一些工作来更改客户端代码以处理 IE8 与世界案例。(感谢 IE8)。
/me 表示 Mozilla 修复了 Firefox 错误。
更新 2:
经过一番挖掘,似乎 IE8XDomainRequest
不能用于发出必须协商 NTLM 的跨域请求,这基本上意味着由于 Web 浏览器的限制,我们的 WCF 绑定的安全性无法使用。
“不会随请求发送身份验证或 cookie”
所以,我想我们现在已经做到了这一点。看起来我们将不得不创建自己的自定义令牌身份验证并将其传递给 cookie 中的 WCF 服务,或者在 IE8 的情况下,POST
它使用 JSON。然后,WCF 服务将不得不处理解密数据并使用它来代替ServiceSecurityContext.Current.WindowsIdentity
我们之前通过 NTLM auth 访问的数据。