Twitter API 授权在浏览器中的 CORS 预检失败

Twitter API authorization fails CORS preflight in browser

我正在尝试 3-legged authorization necessary to call the Twitter APIs in a browser. The process starts with getting a request token by POSTing a signed request to /oauth/request_token (this is also how sign in with Twitter 开头)。

我的问题是,在浏览器 POST 到 Twitter API 端点之前,它想要 preflight the request 使用 OPTIONS 方法。此预检请求始终返回状态 400(错误请求)。

这是一个示例,您可以将其剪切并粘贴到支持 Fetch API 的浏览器控制台中:

fetch('https://api.twitter.com/oauth/request_token', { method: 'POST', mode: 'cors', headers: new Headers({ authorization: 'xxx' }), body: 'oauth_callback=http%3A%2F%2Flocalhost%2F' });

在 Chrome 上,预检请求如下所示(Firefox 类似):

OPTIONS /oauth/request_token HTTP/1.1
accept:*/*
accept-encoding:gzip, deflate, sdch
accept-language:en-US,en;q=0.8
access-control-request-headers:authorization, content-type
access-control-request-method:POST
cache-control:no-cache
origin:null
pragma:no-cache
user-agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36

预检响应如下所示:

HTTP/1.1 400 Bad Request
content-length: 0
date: Tue, 08 Mar 2016 22:21:37 GMT
server: tsa_a
x-connection-hash: 529e3d8338caeb980077637d86db5df1

请注意,问题是 而不是 我在上面的示例中没有指定真正的授权 header。预检请求中未使用授权值 header。

如果我将 POST 请求的组件打印到控制台并将 assemble 这些部分打印到 curl 命令(不预检)中,那么我可以获得请求令牌。但是如果我尝试在 curl 中模拟预检请求,我无法让它工作:

$ curl -v -X OPTIONS -H "access-control-request-headers:authorization,content-type" -H "access-control-request-method:POST" -H "origin:http://example.com" https://api.twitter.com/oauth/request_token
*   Trying 199.59.148.20...
* Connected to api.twitter.com (199.59.148.20) port 443 (#0)
* ALPN, offering http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* successfully set certificate verify locations:
*   CAfile: /opt/local/share/curl/curl-ca-bundle.crt
  CApath: none
* TLSv1.2 (OUT), TLS header, Certificate Status (22):
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Client hello (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-ECDSA-AES128-GCM-SHA256
* ALPN, server accepted to use http/1.1
* Server certificate:
*    subject: C=US; ST=CA; L=San Francisco; O=Twitter, Inc.; OU=Twitter Security; CN=api.twitter.com
*    start date: Aug 11 00:00:00 2015 GMT
*    expire date: Aug 15 12:00:00 2016 GMT
*    subjectAltName: api.twitter.com matched
*    issuer: C=US; O=DigiCert Inc; OU=www.digicert.com; CN=DigiCert SHA2 High Assurance Server CA
*    SSL certificate verify ok.
> OPTIONS /oauth/request_token HTTP/1.1
> Host: api.twitter.com
> User-Agent: curl/7.47.1
> Accept: */*
> access-control-request-headers:authorization,content-type
> access-control-request-method:POST
> origin:http://example.com
> 
< HTTP/1.1 400 Bad Request
< content-length: 0
< date: Tue, 08 Mar 2016 23:06:44 GMT
< server: tsa_a
< x-connection-hash: 66174829ef6d3f5e5ec641ac080ad19c
< 
* Connection #0 to host api.twitter.com left intact

我错过了什么能让我成功完成 https://api.twitter.com/oauth/request_token 的 CORS 预检?

因此,令人不满意的解决方案似乎是 Twitter API does not support CORS。这对我来说似乎有点令人吃惊,因为这意味着 API 不能在浏览器中使用。

该政策决定可能与他们的 OAuth 实施有关,即 vulnerable to anyone with access to the calling platform. Maybe that was okay back in 2010, but most of the other major internet players have figured out how to do client-based authorization

一个解决方法,它是一个 long 解决方法是建立一个代理服务器,你 运行 使用节点或其他东西,我现在已经这样做了几次,对于 运行 关注此问题的人来说,这是一个很好的入门回购。它具有特定于 React 的缺点,但您始终可以撕掉 React ui 并根据需要进行设置:hcra twitter build

它从 Mars Hall 的 Create React App/Node Express 样板中分叉出来

您需要克隆它并 运行 git fetch 然后签出 twitter-req 分支。

一种解决方法是为其创建一个 NodeJS 服务器并调用节点 API 从前端请求 Twitter API。

检查此解决方法:

If you don’t control the server your frontend JavaScript code is sending a request to, and the problem with the response from that server is just the lack of the necessary Access-Control-Allow-Origin header, you can still get things to work—by making the request through a CORS proxy.

简而言之,为请求添加前缀,使完整的 URI 看起来像这样:

https://cors-anywhere.herokuapp.com/https://api.twitter.com/oauth/request_token

遗憾的是,您将无法以这种方式使用大多数 Twitter 库,但您可以继续使用带 cors-anywhere 前缀的 fetch。

编辑:提到的 cors-anywhere 网络服务不再永久可用,而是可以暂时“激活”以供开发使用。

我最近遇到了这个问题。我不想花很多时间创建节点服务器,所以我使用了 Netlify 的无服务器功能。超级简单直接+免费

我关注了这个博客,它非常适合我:https://www.digitalocean.com/community/tutorials/nodejs-solve-cors-once-and-for-all-netlify-dev