如何在预检请求中强制进行身份验证?

How to force authentication in preflight request?

我正在尝试从客户端 javascript(在浏览器中)调用 Github REST API。

我的代码执行以下操作(我正在尝试获取包含私有存储库分支 mkdocs_page 的 zip):

    const endpoint = 'https://api.github.com';
    const resource = '/repos/astariul/private-gh-pages/zipball/mkdocs_page';
    const options = {
      mode: 'cors',
      headers: {
        'Authorization': 'Basic ' + btoa(`${pat}`),  // pat contains my Personal Access Token
      }
    }

    return fetch(`${endpoint}${resource}`, options);

但它不起作用: 预检请求失败,返回 404。

控制台错误信息:

Access to fetch at 'https://api.github.com/repos/astariul/private-gh-pages/zipball/mkdocs_page' from origin 'null' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.


在调试这个过程中,我尝试用curl重现问题。当我指定一个经过身份验证的请求时,它会起作用:

curl --user "<my_PAT_token>" -i https://api.github.com/repos/astariul/private-gh-pages/zipball/mkdocs_page -X OPTIONS

HTTP/1.1 204 No Content

但如果请求未通过身份验证,则不起作用:

curl -i https://api.github.com/repos/astariul/private-gh-pages/zipball/mkdocs_page -X OPTIONS

HTTP/1.1 404 Not Found


注意:当我尝试获取 master 分支(已验证或未验证)时它工作正常。但是在重定向之后它失败了:

Access to fetch at 'https://codeload.github.com/astariul/private-gh-pages/legacy.zip/refs/heads/main?token=XXX' (redirected from 'https://api.github.com/repos/astariul/private-gh-pages/zipball') from origin 'null' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.


这是 Github API 中的错误吗?或者我做错了什么?

无法在预检请求中强制进行身份验证。预检完全由浏览器控制,您可以从前端 JavaScript 代码操作的任何方式都不会暴露它。并且 CORS 协议的要求明确禁止浏览器在预检请求中包含任何凭据。

有关详细说明,请参阅 处的答案。

由于预检涉及浏览器发出 OPTIONS 请求,因此一般来说,如果服务器需要对特定资源的 OPTIONS 请求进行身份验证(这似乎是 GitHub URL 在问题中引用)这根本不一定是意外错误。

这是因为执行预检并发送 OPTIONS 请求的唯一正常情况是浏览器中的前端 JavaScript 代码 运行 的情况。从服务器端代码或 shell/command-line 环境中的代码 运行 或桌面应用程序或本机移动应用程序发出的请求不涉及发送 OPTIONS 请求。

因此,如果提供者实际上打算从浏览器中的前端代码 运行 使用它,则不支持对特定资源的未经身份验证的 OPTIONS 请求只会是一个错误。换句话说,它可以改为指示提供者有意不希望从前端 JavaScript 代码使用它(问题中引用的 URL 似乎就是这种情况)。