python - Gmail API 是否支持使用 OAuth 服务帐户?

标签 python oauth google-api gmail gmail-api

我正在尝试将 Gmail API 与 Python Google Client 库结合使用。

我已经通过 Google Developer Console 创建了一个服务帐户凭据。

然后我尝试使用像 sO 这样的凭据:

from oauth2client.client import SignedJwtAssertionCredentials
client_email = '<sanitised>@developer.gserviceaccount.com'

with open("foobar-<sanitised>.p12") as f:
    private_key = f.read()
    credentials = SignedJwtAssertionCredentials(client_email, private_key, 'https://www.googleapis.com/auth/gmail.readonly')

from httplib2 import Http
http_auth = credentials.authorize(Http())
from apiclient.discovery import build
gmail_server = build('gmail', 'v1', http=http_auth)

但是,当我尝试使用实际的 Gmail API 时,我收到 HTTP 500 错误:

In [13]: threads = gmail_server.users().threads().list(userId='me').execute()
---------------------------------------------------------------------------
HttpError                                 Traceback (most recent call last)
<ipython-input-13-a74134635cc3> in <module>()
----> 1 threads = gmail_server.users().threads().list(userId='me').execute()

/Users/victorhooi/.virtualenvs/kenny/lib/python2.7/site-packages/oauth2client/util.pyc in positional_wrapper(*args, **kwargs)
    133         else: # IGNORE
    134           pass
--> 135       return wrapped(*args, **kwargs)
    136     return positional_wrapper
    137

/Users/victorhooi/.virtualenvs/kenny/lib/python2.7/site-packages/googleapiclient/http.pyc in execute(self, http, num_retries)
    721       callback(resp)
    722     if resp.status >= 300:
--> 723       raise HttpError(resp, content, uri=self.uri)
    724     return self.postproc(resp, content)
    725

HttpError: <HttpError 500 when requesting https://www.googleapis.com/gmail/v1/users/me/threads?alt=json returned "Backend Error">

此处提到的用户显然“服务帐户”不支持使用 GMail API:

https://stackoverflow.com/a/24645874/139137

是否有人能够确认是否属于这种情况,或者 Google 是否在任何地方记录了这种情况?

我的假设是,由于服务帐户凭据是通过用户的 Google Developer Console 创建的,它只会与该用户关联,并且应该可以正常工作?

编辑:

我还应该提到我确实尝试将我的客户端明确添加到 Google Apps 管理控制台中的“管理客户端 API 访问”页面:

enter image description here

但是,我仍然收到 HTTP 500 后端错误。

此外,该页面上的帮助链接指向 OAuth 1.0 特定页面 - 我怀疑该页面仅适用于 OAuth 1.0,尽管此处未明确提及。

编辑 2

此外,我应该提到,我尝试在以下位置使用 Google API Explorer:

https://developers.google.com/apis-explorer/#p/gmail/v1/gmail.users.messages.list?userId=me&_h=1&

使用 OAuth 2.0 和交互式用户流程,它工作正常(即列出电子邮件)。

编辑 3

我尝试按照 Jay Lee 的建议添加 sub 参数。

在我自己的 Google Apps 域中,它确实有效:

from oauth2client.client import SignedJwtAssertionCredentials
client_email = '<sanitised>@developer.gserviceaccount.com'
with open('foo-bar-<sanitised>.p12') as f:
    private_key = f.read()
credentials = SignedJwtAssertionCredentials(client_email, private_key, 'https://www.googleapis.com/auth/gmail.readonly', sub='victorhooi@example.com')
from httplib2 import Http
http_auth = credentials.authorize(Http())
from apiclient.discovery import build
gmail_server = build('gmail', 'v1', http=http_auth)
threads = gmail_server.users().threads().list(userId='me').execute()

然后线程给我:

In [12]: threads
Out[12]:
{u'nextPageToken': u'00058094761552980977',
 u'resultSizeEstimate': 178,
 u'threads': [{u'historyId': u'8942',
   u'id': u'14abc26f1893823b',
   u'snippet': u''},
  {u'historyId': u'8822', u'id': u'14a4ffc2724e9384', u'snippet': u''},
  {u'historyId': u'8769', u'id': u'14a36a9c6f552af3', u'snippet': u''},
  {u'historyId': u'8716', u'id': u'14a31822f19bb161', u'snippet': u''},
  {u'historyId': u'8671', u'id': u'14a2bee13eb87c07', u'snippet': u''},

但是,当我尝试在我的公司 Google Apps 域上使用 sub 参数时,当我到达以下行时:

gmail_server = build('gmail', 'v1', http=http_auth)

这给了我错误:

AccessTokenRefreshError: access_denied: Requested client not authorized.

我相当确定客户端确实存在于 Google Developer 的控制台中,并且 Gmail API 已启用。我只是不确定为什么 sub 参数会触发该错误。

然后,如果我使用公司 Google Apps 域中尚未授权的不同帐户尝试相同的代码,我会得到:

AccessTokenRefreshError: unauthorized_client: Unauthorized client or scope in request.

最佳答案

尝试使用:

credentials = SignedJwtAssertionCredentials(client_email, private_key,
  'https://www.googleapis.com/auth/gmail.readonly', sub='user@domain.com')

其中 user@domain.com 是您要模拟的用户。

关于python - Gmail API 是否支持使用 OAuth 服务帐户?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27810898/

相关文章:

python - DjangoCMS 添加子插件按钮

codeigniter - oAuth 和 Codeigniter 与 MongoDB

node.js - LTI 使用 Node.js 启动身份验证

ios - viewDidLoad 在更新当前位置后重置 Google map View

python - 在 Google App Engine 中管理用户身份验证

python - 跳过父方法的 pythonic 方法是什么?

python - 将 Matplotlib 和 Sympy 的图放在一起

python - 如何在 OpenCV 中计算焦距?

python - Facebook 身份验证 - 有不同的方法吗?

python - 即使 access_type 为 ='offline',Google OAuth2 也不会发布刷新 token ?