使用 transportCredentialOnly 安全性对 RESTful WCF 服务的跨域 Ajax JSON POST 支持
Posted
技术标签:
【中文标题】使用 transportCredentialOnly 安全性对 RESTful WCF 服务的跨域 Ajax JSON POST 支持【英文标题】:Cross domain Ajax JSON POST support against RESTful WCF service using transportCredentialOnly security 【发布时间】:2012-07-05 01:33:08 【问题描述】:我以前就这个主题发过帖子,但是在处理其他事情一年之后,我又设法再次陷入困境。我将尝试简要概述该场景以及当前使事情正常进行的尝试:
在主机上托管 html、JS 等的 IIS Web 服务器:iis.mycompany.com(简称 foo) WCF RESTful Web 服务通过主机上的 Windows 服务托管:wcf.mycompany.com(称为 bar)foo 提供的 javascript 通过对 bar 上的 WCF 服务进行 RESTful ajax 调用(GET
或 POST
,具体取决于操作)来工作,显然这些是跨域调用,因为它们不在同一主机上。
Javascript 使用 jQuery (1.7.2) 框架来操作 DOM 并对 bar 执行 ajax 调用,POSTS
的预期内容类型是 JSON
,而来自 @ 的响应987654329@ 也应该是JSON
(application/json)。
Bar 将其 WCF 服务配置为使用 TransportCredentialOnly
作为安全模式,传输客户端凭据类型为 NTLM
,因此只有经过身份验证的用户才能联系服务。
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.x.x) 似乎不会遇到不协商 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:
经过一番挖掘,似乎 IE8 的 XDomainRequest
不能用于发出必须协商 NTLM 的跨域请求,这基本上意味着由于 Web 浏览器的限制,我们的 WCF 绑定的安全性无法使用。
http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx
“不会随请求发送身份验证或 cookie”
所以,我想我们现在已经做到了这一点。看起来我们将不得不创建自己的自定义令牌身份验证并将其传递给 WCF 服务cookie,或者在 IE8 的情况下,POST
它带有 JSON。然后,WCF 服务必须处理解密数据并使用它来代替我们之前通过 NTLM 身份验证访问的ServiceSecurityContext.Current.WindowsIdentity
。
【问题讨论】:
【参考方案1】:我知道您说过您希望问题本身得到解决,但您可以考虑使用“反向代理”。
我不知道您使用的是什么技术,但我们使用 Apache Web 服务器并在需要身份验证的不同服务器上运行 Java RESTful API。有一段时间,我们搞砸了 JSONP 和 CORS,但并不满意。
最后,我们设置了一个 Apache 反向代理,它创造了奇迹。 Web 浏览器认为它正在与自己的域进行通信并采取适当的行动。 RESTful API 不知道它是通过代理使用的。因此,一切正常。 Apache 做到了所有的魔法。
希望所有的网络服务器都具备像 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
然后重启网络服务器,瞧!
【讨论】:
以上是关于使用 transportCredentialOnly 安全性对 RESTful WCF 服务的跨域 Ajax JSON POST 支持的主要内容,如果未能解决你的问题,请参考以下文章
在使用加载数据流步骤的猪中,使用(使用 PigStorage)和不使用它有啥区别?
Qt静态编译时使用OpenSSL有三种方式(不使用,动态使用,静态使用,默认是动态使用)