从昨天起,我就一直在为这个问题而挣扎。我一直在寻找能帮助其他面临类似问题的人的解决方案,但对我来说什么都不起作用。如果有人能帮助我,我将不胜感激!
我创建了一个项目(名称:xxx),使用应用程序引擎(id:app-xxx)监视GCS bucket(名称:bucket-xxx)。应用程序引擎和bucket在同一个项目中。我试着按照这里列出的步骤:
-
已创建服务帐户(电子邮件:xxx@app-xxx.iam.gserviceaccount.com)使用p12键。
-
列入白名单的URL(属性:https://appxxx.appspot.com)。我在网站管理员搜索控制台中看到了列出的URL。当我使用网站管理员列表API时,也列出了相同的内容。
-
注册域(appxxx.appspot.com/)
-
已将gsutil配置为使用服务帐户"gcloud身份验证激活服务帐户xxx@app-xxx.iam.gserviceaccount.com--密钥文件路径/to/key.p12"。用"gcloud auth-list"命令验证,该命令报告:
凭证账户:-xxx@app-xxx.iam.gserviceaccount.com(活动)
- 让应用程序引擎完全访问GCS铲斗"gsutil acl ch-uapp-xxx@appspot.gserviceaccount.com:FC gs://bucket xxx"
我在开发人员控制台的"权限"页面中看到列出的权限:app-xxx@appspot.gserviceaccount.com(应用程序引擎服务帐户)
我还可以成功地将文件从本地机器上传到GCS bucket xxx:"gsutils cp本地文件gs://bucket xxx/"
但是,当我设置通知时,它会报告:"ServiceException:401未经授权的WebHook回调通道:https://app-xxx.appspot.com/notification"
收到的响应标头显示以下错误:"WWW身份验证:承载领域="https://accounts.google.com/",error=invalid_token"
有什么想法吗?谢谢
当您使用不是应用程序默认服务帐户凭据的服务帐户(即您自己创建的、不是app-xxx@appspot.gserviceaccount.com)。由于无法获取此帐户的p12密钥,因此无法使用gsutil添加手表。
您需要做的是使用JSON API和应用程序的默认服务帐户凭据(AppAssertionCredentials)从应用程序引擎应用程序本身内部添加手表。下面是一个不完整的Python示例(我的默认示例,因为我不知道你的应用程序使用哪种语言),它显示了如何使用谷歌api Python客户端来实现这一点:
from oauth2client.appengine import AppAssertionCredentials
from httplib2 import Http
from apiclient.discovery import build
credentials = AppAssertionCredentials('https://www.googleapis.com/auth/devstorage.read_only')
http_auth = credentials.authorize(Http())
storage = build('storage', 'v1', http=http_auth)
request = service.objects().watchAll(bucket='mybucket', body={args...})
request.execute()
请参阅pydoc以获取watchAll。请注意,您需要将应用程序的默认服务帐户添加到bucket的ACL中才能正常工作(这几乎总是app-id@appspot.gserviceaccount.com,可在开发人员控制台的"权限"部分查看)。
扩展Sevle的答案:即使您从(例如)Secret Manager中检索默认应用程序服务帐户的凭据,然后从中创建客户端,这种情况也会发生。
在一个用TypeScript编写的Firebase项目中,我不得不将代码从更改为
return google.auth.getClient({
credentials,
scopes: ['https://www.googleapis.com/auth/calendar'],
})
.then((client) => {
client.subject = settings.get('apiUser');
return google.calendar({
version: 'v3',
auth: client,
});
});
改为这样工作:
return new GoogleAuth({
scopes: ['https://www.googleapis.com/auth/calendar'],
clientOptions: { subject: settings.get('apiUser') },
}).getClient()
.then((client) =>
google.calendar({
version: 'v3',
auth: client,
})
);
注意,来自第一示例的google.auth.getClient
中的google
与npm上的封装googleapis
绑定,但在第二示例中使用的new GoogleAuth
实际上来自google-auth-library
。
我们稍微改变了应用程序架构,这样我们就不需要在不同的请求上使用不同的服务帐户,所以现在这对我们来说很有效。