8

我以前就这个主题发过帖子,但是在处理其他事情一年之后,我又设法再次陷入困境。我将尝试简要概述该场景以及当前使工作正常进行的尝试:

  • 在主机上托管 HTML、JS 等的 IIS Web 服务器:iis.mycompany.com(简称foo
  • 通过主机上的 Windows 服务托管的 WCF RESTful Web 服务:wcf.mycompany.com(称为bar

foo提供的 Javascript 通过对bar上的 WCF 服务进行 RESTful ajax 调用(GETPOST取决于操作)来工作,显然这些是跨域调用,因为它们不在同一主机上。

Javascript 使用 jQuery (1.7.2) 框架来操作 DOM 并执行对bar的ajax 调用,预期的内容类型POSTS是 is ,并且预期JSON的响应也是 (application/json)。GETSJSON

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 绑定的安全性无法使用。

http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx

“不会随请求发送身份验证或 cookie”

所以,我想我们现在已经做到了这一点。看起来我们将不得不创建自己的自定义令牌身份验证并将其传递给 cookie 中的 WCF 服务,或者在 IE8 的情况下,POST它使用 JSON。然后,WCF 服务将不得不处理解密数据并使用它来代替ServiceSecurityContext.Current.WindowsIdentity我们之前通过 NTLM auth 访问的数据。

4

1 回答 1

1

我知道您说过您希望自己解决问题,但您可以考虑使用“反向代理”。

我不知道您使用的是什么技术,但我们使用 Apache Web 服务器并在需要身份验证的不同服务器上运行 Java RESTful API。有一段时间,我们搞砸了 JSONP 和 CORS,但并不满意。

最后,我们设置了一个 Apache 反向代理,它创造了奇迹。Web 浏览器认为它正在与自己的域进行通信并采取适当的行动。RESTful API 不知道它是通过代理使用的。因此,一切正常。Apache 做了所有的魔法。

希望所有的 Web 服务器都具有像 Apache 的反向代理这样的功能。以下是有关该功能的一些文档:http ://httpd.apache.org/docs/2.2/mod/mod_proxy.html

我们所要做的就是确保安装了 mod_proxy 模块,然后将以下行添加到我们的 Apache 配置文件中:

ProxyPass /restapi http://restfulserver.com/restapi
ProxyPassReverse /restapi http://restfulserver.com/restapi

然后重新启动网络服务器,瞧!

于 2013-12-18T18:41:06.540 回答