我正在编写一个 JavaScript 客户端,将其包含在第 3 方网站上(想想 Facebook Like 按钮)。它需要从需要基本 HTTP 身份验证的 API 检索信息。简化的设置如下所示:
第 3 方网站在其页面上包含此片段:
<script
async="true"
id="web-dev-widget"
data-public-key="pUbl1c_ap1k3y"
src="http://web.dev/widget.js">
</script>
widget.js调用API:
var el = document.getElementById('web-dev-widget'),
user = 'token',
pass = el.getAttribute('data-public-key'),
url = 'https://api.dev/',
httpRequest = new XMLHttpRequest(),
handler = function() {
if (httpRequest.readyState === 4) {
if (httpRequest.status === 200) {
console.log(httpRequest.responseText);
} else {
console.log('There was a problem with the request.', httpRequest);
}
}
};
httpRequest.open('GET', url, true, user, pass);
httpRequest.onreadystatechange = handler;
httpRequest.withCredentials = true;
httpRequest.send();
API 已配置为使用适当的标头进行响应:
Header set Access-Control-Allow-Credentials: true
Header set Access-Control-Allow-Methods: "GET, OPTIONS"
Header set Access-Control-Allow-Headers: "origin, authorization, accept"
SetEnvIf Origin "http(s)?://(.+?\.[a-z]{3})$" AccessControlAllowOrigin=$0
Header set Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
请注意,
Access-Control-Allow-Origin
设置为 Origin
而不是使用通配符,因为我正在发送凭据请求 (withCredentials
)。
现在,发出异步跨域身份验证请求的一切都已就绪,并且在 OS X 10.8.2 上的 Chrome 25 中运行良好。在开发工具中,我可以在
OPTIONS
请求之前看到 GET
请求的网络请求,并且响应按预期返回。
在 Firefox 19 中测试时,Firebug 中不会出现对 API 的网络请求,控制台中会记录此错误:
NS_ERROR_DOM_BAD_URI: Access to restricted URI denied
经过大量挖掘,我发现根据评论,Gecko 不允许用户名和密码直接位于跨站点 URI 中。我认为这是使用可选的用户和密码参数来实现的,所以我尝试了另一种发出经过身份验证的请求的方法,即对凭据进行 Base64 编码并发送授权标头:
open()
这会导致对
// Base64 from http://www.webtoolkit.info/javascript-base64.html
auth = "Basic " + Base64.encode(user + ":" + pass);
...
// after open() and before send()
httpRequest.setRequestHeader('Authorization', auth);
请求的
401 Unauthorized
响应,从而导致 Google 搜索,例如“为什么这在 Chrome 中有效,而在 Firefox 中无效!?”那时我就知道我有麻烦了。为什么可以
它在 Chrome 中工作,而不是在 Firefox 中工作?如何才能一致地发送和响应 OPTIONS
请求?
可以在 Chrome 中工作而不是在 Firefox 中工作? CORS 预检请求的
W3 规范 明确规定应排除用户凭据。 Chrome 和 WebKit 中存在一个错误,其中 OPTIONS
请求返回 401 状态仍会发送后续请求。
有一个相关的错误,以指向 W3 公共 webapps 邮件列表的链接结尾,要求更改 CORS 规范,以允许在 OPTIONS
请求上发送身份验证标头,这对 IIS 用户有利。基本上,他们正在等待这些服务器被淘汰。
OPTIONS
请求?
OPTIONS
请求,无需身份验证。
Kinvey在这方面做得很好,同时还链接到 Twitter API 的一个问题,有趣的是,在提交任何浏览器问题之前几周,概述了这个确切场景的第 22 条军规问题。
OPTIONS
另一个答案中得到了很好的解释,同时Firefox 87+提供了一个解决方法,正如最初解释的那样这里。 自
Firefox 87(2021 年 3 月发布)起,可以在 about:config(即 Firefox 配置编辑器)中设置以下首选项:
<LimitExcept OPTIONS>
AuthType Basic
AuthName <AUTH_NAME>
Require valid-user
AuthUserFile <FILE_PATH>
</LimitExcept>
来自Firefox for Enterprise 87 - 发行说明使用 TLS 客户端证书的公司可以翻转
network.cors_preflight.allow_client_cert: true
首选项,以获得与 Google Chrome 兼容的 CORS 协议处理。特别是,与 Fetch 标准相反,这将传输 TLS 客户端证书以及 CORS 预检。请参阅bug 1511151 了解更多信息。 参考资料: