当提供商因缺少授权标头而拒绝飞行前请求时,让客户端 CORS 工作

Posted

技术标签:

【中文标题】当提供商因缺少授权标头而拒绝飞行前请求时,让客户端 CORS 工作【英文标题】:Getting client-side CORS to work when provider rejects pre-flight requests due to missing authorization header 【发布时间】:2018-06-01 10:23:39 【问题描述】:

我正在开发一个使用 SalesForce API 的 Angular 应用程序(又名 SalesForce“连接应用程序”)。身份验证通过 oAuth/OpenID 进行并且运行良好。但是,该应用目前无法成功访问 SalesForce API 端点,因为:

    这是一个无服务器应用程序,REST 调用是在客户端进行的,AND REST 调用是“不简单的”:它们包含自定义标头(即包含 oAuth 访问令牌的“授权”标头),因此会导致浏览器发出飞行前 OPTIONS 请求; SalesForce 拒绝任何不包含有效“授权”标头和令牌的 API 请求,包括预检,根据定义,它不包括来自初始 GET 请求的自定义标头(实际上飞行前的重点是询问服务器是否允许有问题的自定义标头)。

客户端应用 URL 已添加到 SalesForce 设置中的 CORS 源白名单中,但无效。

这让我完全陷入困境。我无法通过从 REST 调用中删除自定义“授权”标头来避免预飞行,因为将 oAuth 令牌传输到端点的唯一方法是在 URL 参数中,这是不安全的;我无法通过我自己的后端代理请求(即避免前端 CORS 限制),因为它是一个无服务器应用程序;而且我无法让 SalesForce 接受预检,因为它完全在浏览器的控制之下,并且无法修改其标题。

有没有办法配置或强制 SalesForce 接受没有“授权”标头的飞行前 OPTIONS 请求?如果没有,我是否有其他方法可以摆脱这个第 22 条陷阱?

以下是示例代码:

XHR 请求:


  "url": "https://test.salesforce.com/services/oauth2/userinfo",
  "body": null,
  "reportProgress": false,
  "withCredentials": false,
  "responseType": "json",
  "method": "GET",
  "headers": 
    "normalizedNames": [
      
        "key": "accept",
        "value": "Accept"
      ,
      
        "key": "authorization",
        "value": "Authorization"
      
    ],
    "lazyUpdate": null,
    "headers": [
      
        "key": "accept",
        "value": ["application/json"]
      ,
      
        "key": "authorization",
        "value": ["Bearer [...]"] // OAuth token is here
      
    ],
    "lazyInit": null
  ,
  "params": 
    "updates": null,
    "cloneFrom": null,
    "encoder":  HttpUrlEncodingCodec ,
    "map": null
  ,
  "urlWithParams": "https://test.salesforce.com/services/oauth2/userinfo"

根据上述情况向test.salesforce.com:443发出飞行前请求:

OPTIONS /services/oauth2/userinfo HTTP/1.1
Host: test.salesforce.com
Connection: close
Pragma: no-cache
Cache-Control: no-cache
Access-Control-Request-Method: GET
Origin: [...] // client app URL is here
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/63.0.3239.84 Safari/537.36
Access-Control-Request-Headers: authorization
Accept: */*
DNT: 1
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9

对飞行前请求的响应:

HTTP/1.1 403 Forbidden
Date: Fri, 22 Dec 2017 20:16:11 GMT
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Content-Security-Policy: upgrade-insecure-requests 
Referrer-Policy: origin-when-cross-origin
Cache-Control: no-cache,must-revalidate,max-age=0,no-store,private
Set-Cookie: BrowserId=IBrO4jKqQ6qedsWA5DFIcw;Path=/;Domain=.salesforce.com;Expires=Tue, 20-Feb-2018 20:16:11 GMT;Max-Age=5184000
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Connection: close
Content-Length: 19

Missing_OAuth_Token

提前非常感谢!

P.S:这是我在 *** 上发布的第一个问题。我希望它符合标准。如果不是,我提前道歉,我很乐意修改。

【问题讨论】:

首先,您的问题很有道理,因此无需道歉!其次,我很困惑 - 当您发出 GET 请求时,大概您正在传递 Authorization 标头,对吧?所以它也应该在预检 OPTIONS 请求中自动传递......你有任何关于预检 OPTIONS 请求的请求和响应标头的示例吗?我假设您在请求中设置了 withCredentials 标志? 是的,我的 GET 请求包含 Authorization 标头,但我的理解是飞行前请求总是在没有任何自定义标头的情况下发送,因为根据定义,它们的目的是询问它的目标将或获胜'在以后的请求中不接受某个自定义标头。由于这个原因,我相信 withCredentials 标志对飞行前请求也没有影响。 这里是 W3 规范,确认浏览器在飞行前忽略了额外的听众:w3.org/TR/cors/#cross-origin-request-with-preflight-0 @nonAlgebraic 嘿伙计,有什么解决方法吗?我在这里遇到了同样的问题:( 我遇到了完全相同的问题。 Preflight OPTIONS 请求收到 403 响应,因为它不包含带有承载令牌值的授权密钥。你设法解决了这个问题吗? 【参考方案1】:

我怀疑您仍在忙于开发此应用程序,请求来自localhost

还不确定您是否查看了对预飞行的实际响应,以及Access-Control-Allow-Methods 是否包含您尝试调用的 PUT 或 GET 方法?

如果设置正确,Salesforce 绝对支持 CORS。

在 Salesforce 设置中,您可以将跨域资源共享 (CORS) 源列入白名单,然后允许该源执行在 Web 浏览器中运行的代码(例如 javascript)以与 Salesforce 通信。

在 Salesforce 文档中阅读有关此主题的更多信息:

https://developer.salesforce.com/docs/atlas.en-us.chatterapi.meta/chatterapi/extend_code_cors.htm

【讨论】:

是的,客户端应用程序正在本地主机上运行。是的,浏览器触发的OPTIONS飞行前请求包括“Access-Control-Allow-Methods”和“Access-Control-Allow-Headers”头。对预检的响应是 403 Forbidden,以及一条错误消息,抱怨缺少有效的 OAuth 令牌(即“授权”标头 - 正是其存在于发起 GET 请求中触发了预检)。最后,是的,我已在 SalesForce 的 CORS 设置中将来源列入白名单。 我已经完全做到了,并且没有问题地继续进行。您需要发布一些示例代码@nonAlgebraic 很公平!我用一些示例代码编辑了 OP。感谢您的关注。

以上是关于当提供商因缺少授权标头而拒绝飞行前请求时,让客户端 CORS 工作的主要内容,如果未能解决你的问题,请参考以下文章

AugularJS 中的飞行前 OPTIONS 请求未通过授权标头

如果通过 Zuul API 网关发送请求,则缺少授权标头

使用 WCF 的 Http 请求中缺少授权标头

POST请求中缺少授权标头[重复]

如何从 Web 服务提供飞行前请求

我们应该在发送响应时关闭飞行前 Cors 请求的连接吗?