如何使用凭据、HTTP 授权 (CORS) 使 XMLHttpRequest 跨域?
Posted
技术标签:
【中文标题】如何使用凭据、HTTP 授权 (CORS) 使 XMLHttpRequest 跨域?【英文标题】:How to make XMLHttpRequest cross-domain withCredentials, HTTP Authorization (CORS)? 【发布时间】:2014-03-18 00:15:23 【问题描述】:我无法使用 Authorization 标头发出跨域请求(使用 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 值和一个空字符串。我这里没有设置授权标头,但这应该不会影响我读取结果的能力。
如果我尝试将用户名/密码添加到“打开”命令,我会收到 NS_ERROR_DOM_BAD_URI: Access to restricted URI denied
错误。
我做错了什么?
【问题讨论】:
【参考方案1】:我发现与preflight 请求一起使用的唯一方法是:
通过将身份验证逻辑移动到代码(例如从 Apache 到 php)来禁用 OPTIONS 方法请求的身份验证。 使用 jQueryajax
调用 withCredentials
:
$.ajax(
type: 'POST',
xhrFields:
withCredentials: true
,
...
);
令人惊讶的是,如果我只是将 xhr.withCredentials 设置为 true
它不起作用:
$.ajax(
type: 'POST',
beforeSend: function (jqxhr)
jqxhr.withCredentials = true; // This doesn't work
,
...
);
【讨论】:
【参考方案2】:我已经 written an article 完成了 CORS 设置。
我发现了几个可能导致此问题的问题:
-
如果使用凭据,
Access-Control-Allow-Origin
不能是通配符。最简单的方法是将请求的Origin
标头复制到此字段。完全不清楚为什么该标准不允许使用通配符。
即使您清除缓存(可能是会话),Firefox 也会缓存访问控制结果。重新启动迫使它执行一个新的OPTIONS
请求。为了帮助调试,我添加了标题Access-Control-Max-Age: 1
open
命令的用户名/密码显然不能用作凭据。您必须自己添加 Authorization
标头。 xhr.setRequestHeader( 'Authorization', 'Basic ' + btoa( user + ':' + pass ) )
总体而言,withCredentials
系统相当脑残。简单地编写一个接受授权作为请求正文的一部分的服务器会更容易。
【讨论】:
非常感谢!过去一周,我一直在为 CORS 和用户授权而苦苦挣扎。阅读您的答案后,我决定自己进行用户授权。奇迹般有效。是的,“脑死亡”是一个非常贴切的描述。以上是关于如何使用凭据、HTTP 授权 (CORS) 使 XMLHttpRequest 跨域?的主要内容,如果未能解决你的问题,请参考以下文章