问题描述
我尝试使用为Google App Engine上托管的Python 2.7应用创建的oAuth 2.0服务帐户凭证,通过GData API访问Google Spreadsheet。
- 该应用程序使用最近来自Google的gdata-python-client版本2.0.18(gdata和atom)。
- 该应用程序使用最近的google-api -python-client-gae,v。1.2。
- 在此项目的Google开发者控制台中(本例中称为my-gae-app),服务帐户并授予该服务帐户的域名权限
- Google云端硬盘中所需的电子表格属于Google Apps for Work网域,在此称为mygoogleappsdomain.com。 +将电子表格的写入权限设为 [email protected] 并写入显示的电子邮件地址这个服务帐户以及在下面的代码中分配给 clientEmail 变量的变量。不确定两个电子邮件地址中哪一个实际需要,所以我分配了两个。具有 impersonateUser 电子邮件地址的用户也具有对此电子表格的读写权限。
借助Google API Python Client的 AppAssertionCredentials ,我可以通过Google Drive API访问所需电子表格的元数据。但是,如果我尝试使用gdata访问电子表格的内容,则会出现错误。我可以通过服务帐户获得的最好结果是使用 SignedJwtAssertionCredentials ,。然而,我坚持这个 AccessRefreshTokenError:拒绝访问,我不明白发生了什么问题。
import os
从google.appengine.api导入httplib2
从apiclient.discovery导入memcache
从oauth2client.client导入构建
import SignedJwtAssertionCredentials
import gdata.spreadsheets.client
import gdata.spreadsheet.service
在gdata python客户端库
中不支持AppAssertionCredentials,因此我们使用SignedJwtAssertionCredentials和凭证
#此服务帐户的文件。
#在您创建服务帐户时,加载您从Google API
#Console下载的PKCS 12格式的密钥。
clientEmail ='10346 ........- g3dp ...................... [email protected]'
p12File ='app.p12'
path = os.path.join(ROOT_DIR,'data','oAuth2',p12File)
impersonateUser ='[email protected]'
spreadsheetKey ='1mcJHJ ................................... juQMw'#从所需电子表格的URL中复制的ID Google Drive
with open(path)as f:
privateKey = f.read()
f.close()
#使用AppAssertionCredentials获取凭证只能成功
#适用于Python的Google API客户端库,例如访问文件的元数据。
#因此我们使用SignedJwtAssertionCredentials,如
中所示#https://stackoverflow.com/questions/16026286/using-oauth2-with-service-account-on-gdata-in-python
凭证= SignedJwtAssertionCredentials(
clientEmail,
privateKey,
scope =(
'https://www.googleapis.com/auth/drive.file',
#添加了上面提到的其他地方的作用域
#,但是出现了这个作用域的错误
'https://www.googleapis.com/auth/drive',
' https://spreadsheets.google.com/feeds',
'https://docs.google.com/feeds'
),
sub = impersonateUser
)
http = httplib2.Http()
http = credentials.authorize(http)
auth2token = gdata.gauth.OAuth2TokenFromCredentials(凭证)
#会发生错误, SpreadsheetsService()或SpreadsheetsClient()
#srv = gdata.spreadsheet.service.SpreadsheetsService()
#srv = auth2token.author ize(srv)
clt = gdata.spreadsheets.client.SpreadsheetsClient()
clt = auth2token.authorize(clt)
#直到这里没有错误
wks = clt.get_worksheets(spreadsheetKey)
#AccessTokenRefreshError:access_denied
这是错误我得到了远程shell:
s〜my-gae-app> wks = clt.get_worksheets(spreadsheetKey)
Traceback(最近一次调用最后一次):
在< module>文件中的< console>
文件gdata / spreadsheets / client.py,第108行,在get_worksheets
** kwargs)
文件gdata / client.py,第640行,在get_feed中
** kwargs)
请求
uri = uri,auth_token = auth_token,http_request = http_request,** kwargs)
文件gdata / client.py,第267行,文件atom / client.py,第122行,请求
返回self.http_client.request(http_request)
在new_request中输入gdata / gauth.py,第1344行
refresh_response = self._refresh (request_orig)
在_refresh
self.credentials._refresh(httplib2.Http()。request)
文件中的gdata / gauth.py,1485行文件/ usr / local / lib / python2.7 / dist-packages / oauth2client / client.py,第653行,在_refresh
self._do_refresh_request(http_request)
文件中/usr/local/lib/python2.7/dist -packages / oauth2client / client.py,第710行,在_do_refresh_request
中引发AccessTokenRefreshError(error_msg)
AccessTokenRefreshError:access_denied
我不确定这是否表示此服务帐户被拒绝访问电子表格,或者刷新访问令牌时发生错误。你知道这个代码或设置有什么问题吗?
我已经找到了调用 SignedJwtAssertionCredentials 没有子参数(对于模拟用户)不会产生 AccessTokenRefreshError:access_denied $ c
$ p $ import os
从google.appengine.api导入httplib2
导入memcache
from apiclient.discovery import从oauth2client.client创建
import SignedJwtAssertionCredentials
import gdata.spreadsheets.client
import gdata.spreadsheet.service
#AppAssertionCredentials不受支持在gdata python客户端库
#中,所以我们使用带有此服务帐户的凭证
#文件的SignedJwtAssertionCredentials。
#在您创建服务帐户时,加载您从Google API
#Console下载的PKCS 12格式的密钥。
clientEmail ='10346 ........- g3dp ...................... [email protected]'
p12File ='app.p12'
path = os.path.join(ROOT_DIR,'data','oAuth2',p12File)
impersonateUser ='[email protected]'
spreadsheetKey ='1mcJHJ ................................... juQMw'#从所需电子表格的URL中复制的ID Google Drive
with open(path)as f:
privateKey = f.read()
f.close()
#使用AppAssertionCredentials获取凭证只能成功
#适用于Python的Google API客户端库,例如访问文件的元数据。
#因此,我们使用SignedJwtAssertionCredentials,如
#中所建议的一样http://stackoverflow.com/questions/16026286/using-oauth2-with-service-account-on-gdata-in-python
#但不包含子参数!
credentials = SignedJwtAssertionCredentials(
clientEmail,
privateKey,
scope =(
'https://www.googleapis.com/auth/drive.file',
#按照其他地方的建议添加了上述范围,
#但在此范围内发生错误
'https://www.googleapis.com/auth/drive',
'https://spreadsheets.google.com/feeds',
'https://docs.google.com/feeds'
),
#sub = impersonateUser
)
http = httplib2.Http()
http = credentials.authorize(http)
auth2token = gdata.gauth.OAuth2TokenFromCredentials(凭证)
#此模式()
#SpreadsheetsService方法与SpreadsheetsClient不同,但
#srv = gdata.spreadsheet.service.SpreadsheetsService()
#srv = auth2token.authorize(srv)
clt = gdata.spreadsheets.client.SpreadsheetsClient()
clt = auth2token.a uthorize(clt)
wks = clt.get_worksheets(spreadsheetKey)
#现在可以使用!
I'm trying to access a Google Spreadsheet via the GData API using oAuth 2.0 service-account credentials created for a Python 2.7 app hosted on Google App Engine.
- The app uses the recent gdata-python-client from Google, v. 2.0.18 (gdata and atom).
- The app uses the recent google-api-python-client-gae, v. 1.2.
- In the Google Developer Console for this project (in this example referred to as "my-gae-app"), I have created a Service Account and delegated domain-wide authority to the service account as described here
- The desired spreadsheet in Google Drive belongs to a Google Apps for Work domain, here referred to as "mygoogleappsdomain.com".
- I have granted read+write access for the spreadsheet to [email protected] and to the email address shown for this service account and which is assigned to clientEmail variable in the code below. Not sure which of the two email addresses would be actually needed, so I assigned both. The user with the impersonateUser email address also has read+write access to this spreadsheet.
With Google API Python Client's AppAssertionCredentials I can access the meta-data of the desired spreadsheet via the Google Drive API. However, if I try to access the spreadsheet's content using gdata, I'm getting errors. The best result I could get so far with the service account is using SignedJwtAssertionCredentials, as suggested here. However, I'm stuck with this AccessRefreshTokenError: access denied and I don't understand what's going wrong.
import os import httplib2 from google.appengine.api import memcache from apiclient.discovery import build from oauth2client.client import SignedJwtAssertionCredentials import gdata.spreadsheets.client import gdata.spreadsheet.service # AppAssertionCredentials is not supported in gdata python client library, # so we use SignedJwtAssertionCredentials with the credential # file of this service account. # Load the key in PKCS 12 format that you downloaded from the Google API # Console when you created your Service account. clientEmail = '10346........-g3dp......................3m1em8@developer.gserviceaccount.com' p12File = 'app.p12' path = os.path.join(ROOT_DIR, 'data', 'oAuth2', p12File) impersonateUser = '[email protected]' spreadsheetKey = '1mcJHJ...................................juQMw' # ID copied from URL of desired spreadsheet in Google Drive with open(path) as f: privateKey = f.read() f.close() # Getting credentials with AppAssertionCredentials only worked successfully # for Google API Client Library for Python, e.g. accessing file's meta-data. # So we use SignedJwtAssertionCredentials, as suggested in # https://stackoverflow.com/questions/16026286/using-oauth2-with-service-account-on-gdata-in-python credentials = SignedJwtAssertionCredentials( clientEmail, privateKey, scope=( 'https://www.googleapis.com/auth/drive.file ', # added the scope above as suggested somewhere else, # but error occurs with and with-out this scope 'https://www.googleapis.com/auth/drive', 'https://spreadsheets.google.com/feeds', 'https://docs.google.com/feeds' ), sub=impersonateUser ) http = httplib2.Http() http = credentials.authorize(http) auth2token = gdata.gauth.OAuth2TokenFromCredentials(credentials) # error will occur, wether using SpreadsheetsService() or SpreadsheetsClient() #srv = gdata.spreadsheet.service.SpreadsheetsService() #srv = auth2token.authorize(srv) clt = gdata.spreadsheets.client.SpreadsheetsClient() clt = auth2token.authorize(clt) # Until here no errors wks = clt.get_worksheets(spreadsheetKey) # AccessTokenRefreshError: access_denied
This is the error I get in the remote shell:
s~my-gae-app> wks = clt.get_worksheets(spreadsheetKey) Traceback (most recent call last): File "<console>", line 1, in <module> File "gdata/spreadsheets/client.py", line 108, in get_worksheets **kwargs) File "gdata/client.py", line 640, in get_feed **kwargs) File "gdata/client.py", line 267, in request uri=uri, auth_token=auth_token, http_request=http_request, **kwargs) File "atom/client.py", line 122, in request return self.http_client.request(http_request) File "gdata/gauth.py", line 1344, in new_request refresh_response = self._refresh(request_orig) File "gdata/gauth.py", line 1485, in _refresh self.credentials._refresh(httplib2.Http().request) File "/usr/local/lib/python2.7/dist-packages/oauth2client/client.py", line 653, in _refresh self._do_refresh_request(http_request) File "/usr/local/lib/python2.7/dist-packages/oauth2client/client.py", line 710, in _do_refresh_request raise AccessTokenRefreshError(error_msg) AccessTokenRefreshError: access_denied
I'm not sure if this indicates that this service-account is denied access to the spreadsheet, or if there was an error with refreshing the access token. Do you know what's wrong with this code or setup?
I've figured out that calling SignedJwtAssertionCredentials with-out the sub parameter (for the "impersonated" user) will not produce AccessTokenRefreshError: access_denied
import os import httplib2 from google.appengine.api import memcache from apiclient.discovery import build from oauth2client.client import SignedJwtAssertionCredentials import gdata.spreadsheets.client import gdata.spreadsheet.service # AppAssertionCredentials is not supported in gdata python client library, # so we use SignedJwtAssertionCredentials with the credential # file of this service account. # Load the key in PKCS 12 format that you downloaded from the Google API # Console when you created your Service account. clientEmail = '10346........-g3dp......................3m1em8@developer.gserviceaccount.com' p12File = 'app.p12' path = os.path.join(ROOT_DIR, 'data', 'oAuth2', p12File) impersonateUser = '[email protected]' spreadsheetKey = '1mcJHJ...................................juQMw' # ID copied from URL of desired spreadsheet in Google Drive with open(path) as f: privateKey = f.read() f.close() # Getting credentials with AppAssertionCredentials only worked successfully # for Google API Client Library for Python, e.g. accessing file's meta-data. # So we use SignedJwtAssertionCredentials, as suggested in # http://stackoverflow.com/questions/16026286/using-oauth2-with-service-account-on-gdata-in-python # but with-out the sub parameter! credentials = SignedJwtAssertionCredentials( clientEmail, privateKey, scope=( 'https://www.googleapis.com/auth/drive.file ', # added the scope above as suggested somewhere else, # but error occurs with and with-out this scope 'https://www.googleapis.com/auth/drive', 'https://spreadsheets.google.com/feeds', 'https://docs.google.com/feeds' ), # sub=impersonateUser ) http = httplib2.Http() http = credentials.authorize(http) auth2token = gdata.gauth.OAuth2TokenFromCredentials(credentials) # this pattern would eventually also work using SpreadsheetsService() # SpreadsheetsService methods are different from SpreadsheetsClient, though #srv = gdata.spreadsheet.service.SpreadsheetsService() #srv = auth2token.authorize(srv) clt = gdata.spreadsheets.client.SpreadsheetsClient() clt = auth2token.authorize(clt) wks = clt.get_worksheets(spreadsheetKey) # works now!
这篇关于AccessTokenRefreshError:Google Spreadsheet API与App Engine App的oAuth 2.0服务帐户的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!