如何使用带凭据的XMLHttpRequest和HTTP授权(CORS)进行跨域请求?

36

我无法在Firefox中进行带有授权头的跨域请求。我可以进行不需要身份验证的请求,但是一旦我将withCredentials设置为true,就无法再读取来自服务器的响应。

在服务器上,我使用Flask中的after_request方法发送这些标头:

resp.headers['Access-Control-Allow-Origin'] = '*'
resp.headers['Access-Control-Allow-Credentials'] = 'true'
resp.headers['Access-Control-Allow-Methods'] = 'POST, OPTIONS'
resp.headers['Access-Control-Allow-Headers'] = 'Authorization'

Firefox 从未实际进行 OPTIONS 调用。在客户端,我会发起一个 XMLHttpRequest 调用:

var xhr = new XMLHttpRequest()
xhr.open( 'POST', 'http://test.local:8002/test/upload', true)
xhr.withCredentials = true
xhr.onreadystatechange = function() {
    console.log( xhr.status, xhr.statusText )
}
xhr.send(fd)

如果未设置withCredentials,则日志语句将在控制台记录期望的信息。然而,一旦我设置了这个值,xhr就不允许访问,我只会写一个0值和一个空字符串。我没有在这里设置授权标头,但这不应该影响我读取结果的能力。

如果我尝试向"open"命令添加用户名/密码,我会收到NS_ERROR_DOM_BAD_URI: Access to restricted URI denied错误。

我做错了什么?

2个回答

57

我已经写了一篇关于完整CORS设置的文章。文章链接

我发现有几个问题可能导致此问题:

  1. 如果使用凭据,则Access-Control-Allow-Origin不能为通配符。最简单的方法是将请求的Origin头复制到该字段中。标准为什么不允许通配符仍然不清楚。
  2. 即使您清除缓存(也许是会话),Firefox也会缓存Access-Control结果。重新启动浏览器可以强制进行新的OPTIONS请求。为了帮助调试,我添加了头Access-Control-Max-Age:1
  3. open命令的用户名/密码显然不能用作凭证。您必须自己添加Authorization头。xhr.setRequestHeader('Authorization','Basic'+ btoa( user + ':' + pass ))

总体而言,withCredentials系统相当蠢笨。最好的方法是编写一个接受授权作为请求正文的服务器。


1
非常感谢!我在过去的一周里一直在苦苦挣扎CORS和用户授权。一旦我看到了你的答案,我决定自己进行用户授权。现在它可以完美地工作了。是的,“脑残”是一个非常贴切的描述。 - Richard Eng
请注意,第1点“将Origin标头复制到Access-Control响应标头”需要您验证和清理该标头,并根据允许的来源白名单进行检查(除非您真的希望使用带凭据的Access-Control-Allow=*,但没有人会想要这样做)。另一方面,盲目地复制Origin可能会引入严重的漏洞,并且使用不安全的字符串机制复制有效的Origin也可能会这样做。 - jjmontes

2
我发现与Preflight请求一起使用的唯一方法是:
  • 通过将身份验证逻辑从Apache移动到PHP(例如),禁用OPTIONS方法请求的身份验证。
  • 使用带有withCredentials的jQuery ajax调用:
$.ajax({
    type: 'POST',
    xhrFields: {
        withCredentials: true
    },
    ...
});

令人惊讶的是,如果我只是将 xhr.withCredentials 设置为 true,它并不起作用:
$.ajax({
    type: 'POST',
    beforeSend: function (jqxhr) {
        jqxhr.withCredentials = true; // This doesn't work
    },
    ...
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接