如何设置凭据以从 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: &lt;HttpError 403 when requesting https://gmail.googleapis.com/gmail/v1/users/107628233971924038182/labels?alt=json returned "Request had insufficient authentication scopes."&gt;。我在当前目录中看不到我的 tocken.pickle 文件。你知道这可以帮助我们了解发生了什么吗? 正如我之前的评论中提到的,您的 Compute Engine 服务帐户的范围很重要。我用执行此操作的命令更新了我的答案。更改您的虚拟机名称和区域。 我用我的分析/结果更新了你的答案......不幸的是,它仍然无法正常工作 正确,双引号破坏了命令。我更新了脚本。但是,我可以接受您的编辑,因为您建议的范围不正确,并且您失去了当前 VM 的所有范围。让我知道现在是否更好。 您的脚本现在可以了(它将 gmail 范围附加到 VM 的范围列表中)。但是,我仍然收到一个 HttpError,它与第一个不同 (googleapiclient.errors.HttpError: &lt;HttpError 400 when requesting https://gmail.googleapis.com/gmail/v1/users/107628233971924038182/labels?alt=json returned "Precondition check failed."&gt;)。我用更多信息更新了我原来的问题

以上是关于如何设置凭据以从 GCE VM 命令行使用 Gmail API?的主要内容,如果未能解决你的问题,请参考以下文章

如何从命令行设置 android 仪器测试的 vm heapsize

是否可以在不实际部署映像的情况下在 GCE 上配置容器优化的 OS VM?

如何使用命令行的凭据将配置文件发布到 IIS?

更改以从环境变量 PATH 中删除路径

从快照创建的 Windows Server 2012 虚拟机无法在 GCE 上启动

gcloud 组件更新失败