问题描述
我们的公司正在处理来自Google Cloud Platform的Google表格(在Google Drive中)的数据,我们在身份验证方面遇到了一些问题。
我们需要在两个不同的地方运行对Google云端硬盘进行API调用的代码:在Google Compute Engine的生产环境中以及在开发环境中,即在开发人员笔记本电脑上的本地环境中。
我们公司对凭据非常严格,不允许下载服务帐户凭据JSON密钥(这是更好的做法,并且提供更高的安全性)。似乎来自GCP的所有文档都说只需下载服务帐户的JSON密钥并使用它。或Google Api / Developers文档说要创建OAuth2客户端ID并下载其密钥,例如here。
他们经常使用这样的代码:
from google.oauth2 import service_account
ScopES = ['https://www.googleapis.com/auth/sqlservice.admin']
SERVICE_ACCOUNT_FILE = '/path/to/service.json'
credentials = service_account.Credentials.from_service_account_file(
SERVICE_ACCOUNT_FILE,scopes=ScopES)
但是我们不能(或者只是不想)下载我们的服务帐户JSON密钥,因此如果我们只遵循文档,就会陷入困境。
对于Google Compute Engine环境,我们已经能够通过使用GCP应用程序默认凭据(ADC)进行身份验证-即未明确指定要在代码中使用的凭据,并让客户端库“正常工作”-只要可以确保使用正确的作用域https://www.googleapis.com/auth/drive
创建了VM,并且默认的计算服务帐户电子邮件被授予了需要访问的工作表的权限-这在文档here中进行了说明。您可以这样做;
from googleapiclient.discovery import build
service = build('sheets','v4')
SPREADSHEET_ID="<sheet_id>"
RANGE_NAME="A1:A2"
s = service.spreadsheets().values().get(
spreadsheetId=SPREADSHEET_ID,range=RANGE_NAME,majorDimension="COLUMNS"
).execute()
但是,我们该如何进行开发(即在开发人员的笔记本电脑上本地进行)?再说一次,无需下载任何JSON密钥,并且最好采用最“可行的”方法?
通常,我们使用gcloud auth application-default login
来创建默认的应用程序凭据,供Google客户端库使用“可以正常使用”的默认凭据,例如用于Google Storage。但是,这不适用于GCP以外的Google Api,例如Google Drive API service = build('sheets','v4')
失败,并显示以下错误:“请求的身份验证范围不足。”。然后我们尝试了各种解决方案,例如:
credentials,project_id = google.auth.default(scopes=["https://www.googleapis.com/auth/drive"])
和
credentials,project_id = google.auth.default()
credentials = google_auth_oauthlib.get_user_credentials(
["https://www.googleapis.com/auth/drive"],credentials._client_id,credentials._client_secret)
)
还有更多... 当尝试对Google Drive API进行身份验证时,所有这些都会带来无数的错误/问题:(
有什么想法吗?
解决方法
从开发环境轻松进行身份验证的一种方法是使用服务帐户模拟。
Here是一个有关使用服务帐户模拟的博客,包括这样做的好处。 @johnhanley(撰写博客文章的人)是个好人,并且在SO方面也有很多非常有益的答案!
要使您的本地计算机对Google Drive API进行身份验证,您将需要在本地计算机上创建模拟服务帐户的默认应用程序凭据,并为您要访问的API应用所需的范围。
要能够模拟服务帐户,您的用户必须具有角色roles/iam.serviceAccountTokenCreator
。该角色可以应用于整个项目或单个服务帐户。
您可以使用gcloud
来做到这一点:
gcloud iam service-accounts add-iam-policy-binding [COMPUTE_SERVICE_ACCOUNT_FULL_EMAIL] \
--member user:[USER_EMAIL] \
--role roles/iam.serviceAccountTokenCreator
完成此操作后,请创建本地凭据:
gcloud auth application-default login \
--scopes=https://www.googleapis.com/auth/drive,https://www.googleapis.com/auth/userinfo.email,https://www.googleapis.com/auth/cloud-platform,https://www.googleapis.com/auth/accounts.reauth \
--impersonate-service-account=[COMPUTE_SERVICE_ACCOUNT_FULL_EMAIL]
这将解决您遇到的范围错误。在Drive API范围之外添加的三个额外范围是gcloud auth application-default login
应用且必需的默认范围。
如果您应用没有模拟的作用域,则在尝试进行身份验证时会收到如下错误:
HttpError: <HttpError 403 when requesting https://sheets.googleapis.com/v4/spreadsheets?fields=spreadsheetId&alt=json returned "Your application has authenticated using end user credentials from the Google Cloud SDK or Google Cloud Shell which are not supported by the sheets.googleapis.com. We recommend configuring the billing/quota_project setting in gcloud or using a service account through the auth/impersonate_service_account setting. For more information about service accounts and how to use them in your application,see https://cloud.google.com/docs/authentication/.">
设置凭据后,您就可以使用在本地计算机上的Google Compute Engine上运行的相同代码了:)
注意:还可以为所有gcloud命令设置模拟:
gcloud config set auth/impersonate_service_account [COMPUTE_SERVICE_ACCOUNT_FULL_EMAIL]
通过模拟服务帐户在本地计算机上创建默认应用程序凭证是一种认证开发代码的巧妙方法。这意味着该代码将具有与其所模拟的服务帐户完全相同的权限。如果这与将在生产环境中运行代码的服务帐户相同,则您将知道开发中的代码与生产环境中的代码运行相同。这也意味着您不必创建或下载任何服务帐户密钥。