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