xmlHttp.getResponseHeader +不适用于CORS

use*_*547 22 authentication wcf jquery wcf-security cors

我在.NET 4上有一个asp.NET WCF.该服务用于验证用户.我们正在提交用户名和密码,然后应返回包含身份验证cookie的HTTP标头.使用本地托管的测试页面,这是正常的.我现在正在访问头域信息跨域.我已将测试页安装在另一台计算机上,并配置为调用WCF.呼叫正常,呼叫中的"数据"回复正确.但是,我无法使用以下任一方法访问标头信息:

alert(xmlHttp.getAllResponseHeaders());
Run Code Online (Sandbox Code Playgroud)

要么

alert(xmlHttp.getResponseHeader("Set-Cookie"));
Run Code Online (Sandbox Code Playgroud)

使用IE中的调试器和Firefox的"Live HTTP Header"插件,我可以看到正在返回标头信息.

在我的全局ajax页面中,我设置了处理CORS的响应.

private void EnableCrossDomainAjaxCall()
{
    HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");


    if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
    {

        HttpContext.Current.Response.AddHeader("Cache-Control", "no-cache");
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");

        HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
        HttpContext.Current.Response.End();
    }

}
Run Code Online (Sandbox Code Playgroud)

这是我用来调用服务的AJAX:

$("#btnLogin").click(function(e) {
    var geturl;
    geturl = $.ajax({
        // type: "POST",
        type: "GET",
        contentType: "application/json; charset=utf-8",
        url: 'http://10.0.4.66/AuthenticationService.svc/Login?Name=test&password=pwsd',
        // url: '../SecurityServer/AuthenticationService.svc/Login?Name=test&password=pwsd',
        dataType: "jsonp",
        error: function(request, status, error) {
            alert('Error Occured');
        },
        crossdomain: true,
        success: function(data, textStatus, xmlHttp) {
            // alert(xmlHttp.getResponseHeader("Content-Type"));
            document.write(xmlHttp.getResponseHeader("Content-Type") + "<br/>");
            alert(xmlHttp.getAllResponseHeaders());
            alert(xmlHttp.getResponseHeader("Set-Cookie"));
            var headers = '';
            var headerPair = xmlHttp.getAllResponseHeaders('wcfCookie').split("\r\n");
            var output = '';
            $.each(headerPair, function(key, line) {
                var parts = line.split(':');

                if (parts[0] == 'wcfCookie') {
                  ChocChip = parts[1]
                  return false
                }

            });
        }
    });
Run Code Online (Sandbox Code Playgroud)

以下是我从"实时HTTP标头"抓取的标题信息

Date: Mon, 04 Feb 2013 12:12:40 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
X-AspNet-Version: 4.0.30319
Access-Control-Allow-Origin: *
Set-Cookie: wcfCookie=8D38D5D6A0F138FEB595DD016F7694EDDF3E6757C82ED3D419F5047A5294974C1885487465CEC0A0BCC2B3802C7B03FF9F5370A05D4CCBDDDABCB1558C3816044BF4F78209BF38C6B1A7CAD34CD3C85C40B8515CFB1C2B2694BC78803D8DACB4
Content-Length: 65
Cache-Control: application/json; charset=utf-8
Content-Type: application/x-javascript
Run Code Online (Sandbox Code Playgroud)

aps*_*ers 65

首先,一点背景:

您正在使用Access-Control-Allow-Headers,它指定允许客户端发送哪些请求标头,但您没有指定允许客户端读取哪些响应标头.要允许客户端读取非简单响应标头,您需要使用.来自HTML5 Rocks CORS页面:Access-Control-Expose-Headers

在CORS请求期间,该getResponseHeader()方法只能访问简单的响应头.简单响应头定义如下:

  • 缓存控制
  • 内容语言
  • 内容类型
  • 过期
  • 最后修改
  • 附注

如果您希望客户端能够访问其他标头,则必须使用Access-Control-Expose-Headers标头.此标头的值是您要向客户端公开的响应标头的逗号分隔列表.

所以,鉴于这些新信息,您可以:

HttpContext.Current.Response.AddHeader("Access-Control-Expose-Headers", "Set-Cookie");
Run Code Online (Sandbox Code Playgroud)

......但还有更多.

现在,实际答案:

这里还有一个更严重的问题:XHR规范明显不允许阅读Set-Cookie.那是因为这在功能上是一个跨域cookie偷窃攻击.

假设域A向域B发出跨域请求.当域B设置cookie时,它仅为域B设置域特定的cookie .域A读取域B的cookie的任何尝试都违反了cookie访问的同源策略.

我不知道WCF,所以我不确定实际做你想做的最好的方法,但我猜测解决方案可能是通过一个身份验证令牌而不是通过cookie(例如,一个X-WCF-Auth头?)那个域A读取然后设置自己的cookie.


mar*_*rty 2

浏览器的安全策略可能会阻止您的响应,因为您尚未设置:

HttpContext.Current.Response.AddHeader("Access-Control-Allow-Credentials","true");
Run Code Online (Sandbox Code Playgroud)

如果这没有帮助,请尝试添加

xhrFields: { withCredentials: true }
Run Code Online (Sandbox Code Playgroud)

您的ajax选择可能也值得一试。