问题描述
我已经配置了执行GCF的云端点。当云运行服务允许allUsers
调用API时,一切正常。
一旦我删除allUsers
并使用服务帐户进行身份验证,云运行控制台中将显示403错误:
请求未通过验证。允许未经身份验证的调用或设置适当的Authorization标头。在https://cloud.google.com/run/docs/securing/authenticating
中了解更多信息
可从原始位置访问“ https://.run.app/do-this&key=” “ http://0.0.0.0:8080”已被CORS政策阻止:未响应预检请求 通过访问控制检查:请求中不存在“ Access-Control-Allow-Origin”标头 资源。如果不透明的响应满足您的需求,请将请求的模式设置为“ no-cors”以获取 禁用了CORS的资源。
这是我在浏览器中运行的JS代码:
let options: Requestinit = {
headers: {
'Authorization': `Bearer ${token}`,},}
const result = await fetch(fetchURL,options);
使用相同令牌运行curl时,我得到了预期的响应
curl -H "Authorization: Bearer ${token}" 'https://<my-api>.run.app/do-this&key=<key>'
出于完整性考虑,这里也是端点yaml
swagger: '2.0'
info:
title: My first widget
description: This is a great widget
version: 1.0.0
host: <my-api>.run.app
schemes:
- https
produces:
- application/json
paths:
/do-this:
get:
summary: Do-this
operationId: doit
x-google-backend:
address: https://<project-id>.cloudfunctions.net/do-that
responses:
'200':
description: A successful response.
schema:
type: string
'403':
description: An error occurred
schema:
type: string
security:
- api_key: []
securityDeFinitions:
# This section configures basic authentication with an API key.
api_key:
type: "apiKey"
name: "key"
in: "query"
更新esp的命令:
gcloud run services update <my-api> --set-env-vars="^|^ENDPOINTS_SERVICE_NAME=<my-api>.run.app|ESP_ARGS=--rollout_strategy=managed,--cors_preset=basic" --project=<project-id> --platform=managed --region=europe-west1
更新
启用cors浏览器端无济于事。
Google文档提到应该call from outside GCP
如果您要从无法访问计算元数据的计算实例(例如您自己的服务器)调用服务,则必须手动生成适当的令牌:
使用target_audience声明设置为接收服务URL的服务帐户JWT自签名。 将自签名的JWT交换为Google签名的ID令牌,该令牌应将aud声明设置为上述URL。 将ID令牌包括在对服务的请求中的Authorization:Bearer ID_TOKEN标头中。 尽管Cloud Run(完全托管)尚不支持身份识别代理,但是您可以检查身份识别代理示例代码,以获取上述步骤的代码示例。
The end-users section:尽管提及CORS
构建Web应用程序时,必须解决跨域资源共享(CORS)问题。例如,发送的CORS预检请求没有Authorization标头,因此它们在非公共服务上被拒绝。因为预检请求失败,所以主请求也将失败。
要解决此问题,您可以将您的Web应用程序和服务托管在同一域中,以避免CORS的预检请求。您可以使用Firebase托管来实现。
我尝试在Firebase托管上托管JS脚本和HTML,但问题仍然存在。
想到的另一个问题是:我是否需要在开放api规范中同时设置OAuth和API密钥身份验证?
更新2
This discussion建议无法将Cloud Run与支持CORS的身份验证一起使用。我还想知道为什么会卷曲。我正在使用服务帐户令牌进行身份验证,而不是最终用户。
解决方法
未为Cloud Endpoint激活cors。像这样更新您的openAPI规范
IloCplex mycplex = new IloCplex();
int Ncd=2;
int Nbv=6;
int T=4;
IloNumVar[][][][] y = new IloIntVar[Ncd][][][];
for(int i=0; i<y.length;i++) {
y[i]= new IloIntVar[Ncd][][];
for(int j=0; j<y[i].length;j++) {
y[i][j]= new IloIntVar[Nbv+1][];
for(int k=1; k<y[i][j].length; k++) {
y[i][j][k]= mycplex.boolVarArray(T+1);
for(int t=1; t<T; t++)
{
IloRange myConstraint2 = mycplex.addEq(y[i][j][k][t],1);
mycplex.add(myConstraint2);
}
}
}
}
mycplex.solve();
for (int i = 0; i < Ncd; i++) {
for (int j = 0; j < Ncd; j++) {
for (int k = 1; k < Nbv; k++) {
for(int t=1; t<T; t++)
System.out.printf("valeur = "+mycplex.getValue(y[i][j][k][t]));
}
}
}
或按照错误消息的说明设置swagger: '2.0'
info:
title: My first widget
description: This is a great widget
version: 1.0.0
host: <my-api>.run.app
x-google-endpoints:
- name: <my-api>.run.app
allowCors: True
...
...
...
来签入您的电话。
我通过以下方式使其工作:
- 将
oauth
作为安全性定义添加到OpenAPI规范中,并将其与每个API路径的api密钥一起使用 - 使用
--set-env-vars="^|^ENDPOINTS_SERVICE_NAME=<my-api>.run.app|ESP_ARGS=--cors_preset=basic,--rollout_strategy=managed"
部署端点 - 在Cloud Function中,将
Access-Control-Allow-Origin
设置为空字符串''
:res.setHeader("Access-Control-Allow-Origin",'')
- 允许
allUsers
可以访问Cloud Run容器
每个人都可以访问Cloud Run容器时,端点将负责身份验证。
令我惊讶的是,CF自动在mydomain.com
标头中添加了呼叫主机(例如*
)和Access-Control-Allow-Origin
。此标头中不允许使用多个项目,因此我放弃了mydomain.com
并保留了*
。
我将尝试使用不同的选项,完成后将提供所有步骤的操作方法。任何意见/建议都非常感谢!
更新
深入研究之后,我了解到Access-Control-Allow-Origin
会自动添加const cors = require('cors')({origin: true});
对于我的用例,我不需要CF内的cors,因为只能从Cloud Run ESP中访问它们。
因此重要的步骤是:
- 将oauth添加到OpenAPI规范
- 通过ESP_ARGS启用cors
- 允许
allUsers
可以访问云运行容器