Gmail API 是否支持使用 OAuth 服务帐户?
问题描述
我正在尝试将 Gmail API 与 Python Google 客户端库一起使用.
我已通过 Google 开发者控制台创建了一个服务帐户凭据.
然后我尝试使用像 sO 这样的凭据:
从 oauth2client.client 导入 SignedJwtAssertionCredentialsclient_email = '<sanitised>@developer.gserviceaccount.com'使用 open("foobar-<sanitised>.p12") 作为 f:private_key = f.read()凭据 = SignedJwtAssertionCredentials(client_email, private_key, 'https://www.googleapis.com/auth/gmail.readonly')从 httplib2 导入 Httphttp_auth = credentials.authorize(Http())从 apiclient.discovery 导入构建gmail_server = build('gmail', 'v1', http=http_auth)
但是,当我尝试使用实际的 Gmail API 时,我收到了 HTTP 500 错误:
在 [13] 中:threads = gmail_server.users().threads().list(userId='me').execute()---------------------------------------------------------------------------HttpError Traceback(最近一次调用最后一次)<ipython-input-13-a74134635cc3>在<模块>()---->1 个线程 = 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 其他:#忽略134 次通过-->135返回包装(*args,**kwargs)第136章137/Users/victorhooi/.virtualenvs/kenny/lib/python2.7/site-packages/googleapiclient/http.pyc 在执行(自我,http,num_retries)721 回调(响应)722 如果 resp.status >= 300:-->第723章第724章725HttpError:<HttpError 500 当请求 https://www.googleapis.com/gmail/v1/users/me/threads?alt=json 返回后端错误">
这里的一位用户提到,服务帐户"显然不支持使用 GMail API:
p>
使用 OAuth 2.0 和交互式用户流程,它运行良好(即它列出了电子邮件).
编辑 3
我尝试按照 Jay Lee 的建议添加 sub
参数.
在我自己的 Google Apps 域中,它确实有效:
从 oauth2client.client 导入 SignedJwtAssertionCredentialsclient_email = '<sanitised>@developer.gserviceaccount.com'使用 open('foo-bar-<sanitised>.p12') 作为 f:private_key = f.read()凭据 = SignedJwtAssertionCredentials(client_email, private_key, 'https://www.googleapis.com/auth/gmail.readonly', sub='victorhooi@example.com')从 httplib2 导入 Httphttp_auth = credentials.authorize(Http())从 apiclient.discovery 导入构建gmail_server = build('gmail', 'v1', http=http_auth)线程 = gmail_server.users().threads().list(userId='me').execute()
然后线程给了我:
在[12]中:线程输出[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: 请求的客户端未授权.
我相当确定客户端确实存在于 Google 开发者的控制台中,并且启用了 Gmail API.我只是不确定为什么 sub
参数会触发该错误.
然后,如果我使用公司 Google Apps 域中的不同帐户尝试相同的代码,但尚未委托,我会得到:
AccessTokenRefreshError:未授权客户端:请求中的未授权客户端或范围.
解决方案 尝试使用:
credentials = SignedJwtAssertionCredentials(client_email, private_key,'https://www.googleapis.com/auth/gmail.readonly', sub='user@domain.com')
其中 user@domain.com 是您要模拟的用户.
I am trying to use the Gmail API with the Python Google Client library.
I have created a Service Account credential through the Google Developer Console.
I am then attempting to use those credentials like 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)
However, when I try to use the actual Gmail API, I get an HTTP 500 error:
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">
A user mentioned here that apparently the "Service Accounts" do not support using the GMail API:
https://stackoverflow.com/a/24645874/139137
Is anybody able to confirm if this is the case, or if it's documented by Google anywhere?
My assumption was that since the Service Account credentials were created through a user's Google Developer Console, it would just be associated with that user, and should work fine?
EDIT:
I should also mentioned I did try explicitly adding my client to the "Managing Client API Access" page in the Google Apps Admin Console:
However, I am still getting the HTTP 500 Backend Error.
Also, the help links on that page go to a OAuth 1.0 specific page - I have a suspicion that this page is only for OAuth 1.0, although it's not explicitly mentioned there.
EDIT 2
Also, I should mentioned that I tried using the Google API Explorer at:
https://developers.google.com/apis-explorer/#p/gmail/v1/gmail.users.messages.list?userId=me&_h=1&
using OAuth 2.0 and the interactive user flow, and it works fine (i.e. it lists emails).
EDIT 3
I tried adding the sub
argument as suggested by Jay Lee.
On my own Google Apps domain, it does actually work:
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()
And then threads gives me:
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''},
However, when I try using the sub argument on my corporate Google Apps domain, when I get to the following line:
gmail_server = build('gmail', 'v1', http=http_auth)
This gives me the error:
AccessTokenRefreshError: access_denied: Requested client not authorized.
I'm fairly certain that client does exist in the Google Developer's console, and the Gmail API is enabled. I'm just not sure why the sub
argument triggers that error.
And then, if I try the same code using a different account on the corporate Google Apps domain, that hasn't been Delegated, I get:
AccessTokenRefreshError: unauthorized_client: Unauthorized client or scope in request.
解决方案
Try using:
credentials = SignedJwtAssertionCredentials(client_email, private_key,
'https://www.googleapis.com/auth/gmail.readonly', sub='user@domain.com')
where user@domain.com is the user you wish to impersonate.
相关文章