Google 来自服务帐户的任务队列验证与已安装的应用凭据

Google Task Queue auth from service account vs installed app credentials

总结: 使用已安装的(本机)应用程序凭据,我能够授权和使用拉取任务队列——使用 OAuth2 和 REST API v1beta2。这没关系,但我更愿意在 服务帐户 下授权和使用任务队列,因为使用已安装的应用程序凭据需要我在任务队列 ACL 中使用我自己的电子邮件地址(请参阅以下)。但是,当我授权使用服务帐户(双腿 Oauth2)时,将服务帐户电子邮件地址添加到队列 ACL 后,我在使用队列时遇到权限错误。 有没有办法从本地客户端应用程序使用服务帐户下的任务队列?

详细信息:我对任务队列 ACL 有点困惑,它使用电子邮件地址指定权限——安装的应用程序凭据似乎没有关联的电子邮件地址。但基本上,当您首次通过三足 OAuth 授权时,它会使用您在浏览器中登录的任何 google 帐户。所以当我在队列 ACL 下包含我自己的电子邮件地址时,它工作正常:

queue:
- name: my-queue
  mode: pull
  acl:
  - user_email: my-email@example.com
  - writer_email: my-email@example.com

但是,如果我以相同的方式添加我的服务帐户电子邮件地址,并使用该服务帐户进行授权,我会收到错误 403:you are not allowed to make this api call.

queue:
- name: my-queue
  mode: pull
  acl:
  - user_email: 12345-abcd@developer.gserviceaccount.com
  - writer_email: 12345-abcd@developer.gserviceaccount.com

我仔细检查了服务电子邮件地址是否正确,并尝试在 queue.yaml 文件中引用它,得到同样的错误。

这向我表明任务队列出于某种原因没有将我的授权与服务帐户电子邮件地址相关联。要么它不喜欢 2-legged OAuth,要么其他?

请注意,服务帐户授权本身 确实 有效(下面的 ruby 代码),但随后的 API 调用无效,并且显然 ACL 权限是错误的直接原因。

# issuer == service account email address

def service_auth!(issuer, p12_file)
  key = Google::APIClient::KeyUtils.load_from_pkcs12(p12_file, 'notasecret')
  client.authorization = Signet::OAuth2::Client.new(
    :token_credential_uri => 'https://accounts.google.com/o/oauth2/token',
    :audience => 'https://accounts.google.com/o/oauth2/token',
    :scope => 'https://www.googleapis.com/auth/prediction',
    :issuer => issuer,
    :signing_key => key)
  client.authorization.fetch_access_token!

  api = client.discovered_api(TASKQUEUE_API, TASKQUEUE_API_VERSION)

  return client, api
end

我认为问题可能只是你的范围('https://www.googleapis.com/auth/prediction')。

我可以使用服务帐户授权并调用 TaskQueue API,没有任何问题。我的示例在 Python 但是(抱歉我不是 Rubyist):

queue.yaml:

queue:
- name: pull
  mode: pull
  retry_parameters:
    task_retry_limit: 5
  acl:
  - user_email: 12345-abcd@developer.gserviceaccount.com
  - writer_email: 12345-abcd@developer.gserviceaccount.com

来源:

client_email = '12345-abcd@developer.gserviceaccount.com'

with open('service_account.p12', 'rb') as f:
  private_key = f.read()

credentials = SignedJwtAssertionCredentials(client_email, private_key,
    ['https://www.googleapis.com/auth/taskqueue',
     'https://www.googleapis.com/auth/taskqueue.consumer'])

http = httplib2.Http()
http = credentials.authorize(http)

api = build('taskqueue', 'v1beta2', http=http)   

# Do stuff with api ...