如何设置凭据以从 GCE VM 命令行使用 Gmail API?
Posted
技术标签:
【中文标题】如何设置凭据以从 GCE VM 命令行使用 Gmail API?【英文标题】:How to set credentials to use Gmail API from GCE VM Command Line? 【发布时间】:2021-02-23 19:00:36 【问题描述】:我正在尝试在 GCE 上启用我的 Linux VM 以访问我的 Gmail 帐户以发送电子邮件。
我找到了这篇文章,https://developers.google.com/gmail/api/quickstart/python,它读取了一些 Gmail 帐户信息(它很有用,因为我只是想测试我的连接)。
from __future__ import print_function
import pickle
import os.path
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
# If modifying these scopes, delete the file token.pickle.
SCOPES = ['https://www.googleapis.com/auth/gmail.readonly']
def main():
"""Shows basic usage of the Gmail API.
Lists the user's Gmail labels.
"""
creds = None
# The file token.pickle stores the user's access and refresh tokens, and is
# created automatically when the authorization flow completes for the first
# time.
if os.path.exists('token.pickle'):
with open('token.pickle', 'rb') as token:
creds = pickle.load(token)
# If there are no (valid) credentials available, let the user log in.
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(
'credentials.json', SCOPES)
creds = flow.run_local_server(port=0)
# Save the credentials for the next run
with open('token.pickle', 'wb') as token:
pickle.dump(creds, token)
service = build('gmail', 'v1', credentials=creds)
# Call the Gmail API
results = service.users().labels().list(userId='me').execute()
labels = results.get('labels', [])
if not labels:
print('No labels found.')
else:
print('Labels:')
for label in labels:
print(label['name'])
if __name__ == '__main__':
main()
但是,我不确定我需要设置哪些凭据,就像我设置和使用时一样:
服务帐号:我收到以下消息ValueError: Client secrets must be for a web or installed app.
Web 应用程序类型的 OAuth 客户端 ID:代码运行良好,但在尝试首次授权应用程序访问时收到以下消息:
错误 400:redirect_uri_mismatch 请求中的重定向 URI http://localhost:60443/ 与授权给 OAuth 客户端的重定向 URI 不匹配。要更新授权的重定向 URI,请访问:https://console.developers.google.com/apis/credentials/oauthclient/$your_client_id?project=$your_project_number
-
桌面类型的 OAuth 客户端 ID:代码运行良好,但是在尝试首次授权应用程序访问时收到以下消息:
本地主机连接被拒绝
有谁知道正确的设置以及我是否遗漏了什么?
谢谢
[11 月 17 日]
将 gmail 范围添加到我的 VM 范围后,我运行了 python 脚本,但出现以下错误:
Traceback (most recent call last):
File "quickstart2.py", line 29, in <module>
main()
File "quickstart2.py", line 18, in main
results = service.users().labels().list(userId="107628233971924038182").execute()
File "/home/lucasnunesfe9/.local/lib/python3.7/site-packages/googleapiclient/_helpers.py", line 134, in positional_wrapper
return wrapped(*args, **kwargs)
File "/home/lucasnunesfe9/.local/lib/python3.7/site-packages/googleapiclient/http.py", line 915, in execute
raise HttpError(resp, content, uri=self.uri)
googleapiclient.errors.HttpError: <HttpError 400 when requesting https://gmail.googleapis.com/gmail/v1/users/107628233971924038182/labels?alt=json returned "Precondition check failed.">
我检查了错误的 HTTP 链接,它显示:
"error":
"code": 401,
"message": "Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
"errors": [
"message": "Login Required.",
"domain": "global",
"reason": "required",
"location": "Authorization",
"locationType": "header"
],
"status": "UNAUTHENTICATED"
“第一个授权步骤”是否需要任何手动程序?
PS:强调我已经将我的服务帐户启用为“G Suite 域范围委派”。此操作生成了一个 OAuth 2.0 客户端 ID,该 ID 正在 python 脚本中使用(变量 userId)。
【问题讨论】:
试试Google-auth library。使用默认凭据模式(ADC) ->credentials, project_id = google.auth.default()
。考虑正确确定 Compute Engine 的范围。如果您有问题,请在您的问题中添加更多详细信息,我将为您提供完整的答案
嗨@guillaumeblaquiere,我不确定您的建议是否适合脚本(我已将其添加到我的问题中)。看到这段代码:“flow = InstalledAppFlow.from_client_secrets_file('credentials.json', SCOPES)” ...要求一个文件路径,包括客户端机密。此外,该脚本适用于“此示例中的授权流程是为命令行应用程序设计的”。所以,我在虚拟机中努力这样做似乎很奇怪。只是为了强调,这个虚拟机是在谷歌云引擎中实例化的。
【参考方案1】:
就我个人而言,我从来没有理解过这个例子。我认为它太旧了(甚至兼容 Python 2.6!!)
不管怎样,你可以忘记第一部分并获得这样的证书
from googleapiclient.discovery import build
import google.auth
# If modifying these scopes, delete the file token.pickle.
SCOPES = ['https://www.googleapis.com/auth/gmail.readonly']
def main():
creds, project_id = google.auth.default(scopes=SCOPES)
service = build('gmail', 'v1', credentials=creds)
# Call the Gmail API
results = service.users().labels().list(userId='me').execute()
labels = results.get('labels', [])
if not labels:
print('No labels found.')
else:
print('Labels:')
for label in labels:
print(label['name'])
if __name__ == '__main__':
main()
但是,由于您将使用服务帐户来访问您的 GMAIL 帐户,因此您必须将 userId 更改为您想要的 ID,并从 GSuite 管理控制台访问服务帐户才能访问 GMAIL API .
要实现这一点,您需要授予 VM 服务帐户的范围。停止 VM,运行此(长)命令,然后再次启动 VM。命令:
获取 VM 的当前范围(并清理/格式化它们) 添加 gmail 范围 将范围设置为 VM(这是一个 BETA 命令)gcloud beta compute instances set-scopes <YOUR_VM_NAME> --zone <YOUR_VM_ZONE> \
--scopes=https://www.googleapis.com/auth/gmail.readonly,\
$(gcloud compute instances describe <YOUR_VM_NAME> --zone <YOUR_VM_ZONE> \
--format json | jq -c ".serviceAccounts[0].scopes" | sed -E "s/\[(.*)\]/\1/g" | sed -E "s/\"//g")
【讨论】:
嗨@guillaume,我尝试了您建议的脚本,并且我已启用我的服务帐户以具有 G Suite 域范围的委派访问权限(并且我在脚本中使用了我的用户 ID)。但是,我收到了以下消息:googleapiclient.errors.HttpError: <HttpError 403 when requesting https://gmail.googleapis.com/gmail/v1/users/107628233971924038182/labels?alt=json returned "Request had insufficient authentication scopes.">
。我在当前目录中看不到我的 tocken.pickle 文件。你知道这可以帮助我们了解发生了什么吗?
正如我之前的评论中提到的,您的 Compute Engine 服务帐户的范围很重要。我用执行此操作的命令更新了我的答案。更改您的虚拟机名称和区域。
我用我的分析/结果更新了你的答案......不幸的是,它仍然无法正常工作
正确,双引号破坏了命令。我更新了脚本。但是,我可以接受您的编辑,因为您建议的范围不正确,并且您失去了当前 VM 的所有范围。让我知道现在是否更好。
您的脚本现在可以了(它将 gmail 范围附加到 VM 的范围列表中)。但是,我仍然收到一个 HttpError,它与第一个不同 (googleapiclient.errors.HttpError: <HttpError 400 when requesting https://gmail.googleapis.com/gmail/v1/users/107628233971924038182/labels?alt=json returned "Precondition check failed.">
)。我用更多信息更新了我原来的问题以上是关于如何设置凭据以从 GCE VM 命令行使用 Gmail API?的主要内容,如果未能解决你的问题,请参考以下文章
如何从命令行设置 android 仪器测试的 vm heapsize
是否可以在不实际部署映像的情况下在 GCE 上配置容器优化的 OS VM?