未经授权的 WebHook 回调通道

Unauthorized WebHook callback channel

从昨天开始我就一直在为这个问题苦苦挣扎。寻找可以帮助其他遇到类似问题的人的解决方案,但对我没有任何帮助。如果有人能帮助我,我将不胜感激!

我创建了一个项目(名称:xxx),应用引擎(id:app-xxx)监视 GCS 存储桶(名称:bucket-xxx)。 App Engine 和 bucket 在同一个项目中。我尝试按照 here 列出的步骤进行操作:

  1. 使用 p12 密钥创建服务帐户(电子邮件:xxx@app-xxx.iam.gserviceaccount.com)。

  2. 白名单 URL (属性: https://app-xxx.appspot.com)。我在网站管理员搜索控制台中看到了 URL。我用站长列表API.

  3. 的时候也是一样的
  4. 注册域名(app-xxx.appspot.com/)

  5. 已将 gsutil 配置为使用服务帐户 "gcloud auth activate-service-account xxx@app-xxx.iam.gserviceaccount.com --key-file path/to/key.p12"。使用 "gcloud auth list" 命令验证,报告:

认证帐户: - xxx@app-xxx.iam.gserviceaccount.com(活跃)

  1. 授予应用引擎对 GCS 存储桶的完全访问权限 "gsutil acl ch -u app-xxx@appspot.gserviceaccount.com:FC gs://bucket-xxx"

我在开发者控制台的“权限”页面中看到权限列表: app-xxx@appspot.gserviceaccount.com(App 引擎服务帐户)

我也可以成功将文件从本地计算机上传到 GCS bucket-xxx: "gsutils cp local-file gs://bucket-xxx/"

但是,当我设置通知时,它报告: "ServiceException: 401 Unauthorized WebHook callback channel: https://app-xxx.appspot.com/notification"

收到的响应 header 显示以下错误: "WWW-Authenticate: Bearer realm="https://accounts.google.com/",错误=invalid_token"

知道这里可能有什么问题吗?谢谢!

当您使用不是应用程序默认服务帐户凭据的服务帐户(即您自己创建的,不是应用程序- xxx@appspot.gserviceaccount.com)。由于无法获取此帐户的 p12 密钥,因此您将无法使用 gsutil 添加手表。

您需要做的是从 App Engine 应用程序内部添加手表,使用 JSON API and the application's default service account credentials (AppAssertionCredentials). Here's an incomplete Python example (my default since I don't know which language your app uses) which shows how this might be accomplished which uses the google-api-python-client:

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()

请参阅 watchAll 的 pydoc。请注意,您需要将应用程序的默认服务帐户添加到存储桶的 ACL 才能正常工作(几乎总是 app-id@appspot.gserviceaccount.com,可在开发者控制台的 'Permissions' 部分查看)。

只是为了扩展 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.

我们稍微更改了应用程序架构,因此我们不需要针对不同的请求使用不同的服务帐户,所以这现在对我们有用。