使用transportCredentialOnly安全性对RESTful WCF服务提供跨域Ajax JSON POST



我以前就这个主题发表过文章,但在处理了一年其他事情之后,我又一次陷入了困境。我将尝试简要概述该场景和当前使事情正常运行的尝试:

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

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

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

Bar的WCF服务使用TransportCredentialOnly作为安全模式进行配置,并且传输客户端凭据类型为NTLM,因此只有经过身份验证的用户才能联系这些服务。

CORS支持已添加到bar的WCF服务中,使用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的传输安全绑定配置有关,但我不确定。

此外,我对此没有太多经验,但在执行跨域请求时,我没有看到太多关于使用application/json内容类型的POST的信息,而不是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">

所以,我想我们现在已经做到了。。看起来我们必须创建自己的自定义令牌身份验证,并将其以cookie的形式传递给WCF服务,或者在IE8的情况下,将其与JSON一起传递给POST。WCF服务将不得不处理解密数据并使用它,而不是我们以前使用NTLM身份验证访问的ServiceSecurityContext.Current.WindowsIdentity

我知道你说过你宁愿问题本身得到解决,但你可以考虑使用"反向代理">

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

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

希望所有的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

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

相关内容

  • 没有找到相关文章

最新更新