开始使用Google API:工作区(3/3)
#python #node #googlecloud #googleapi

介绍

您是开发人员,但是使用Google API的完整初学者吗?该系列适合您,因为我向您展示了如何从头开始,从Google Workspace(“ GWS”)API(例如Google Drive和Sheets)开始。 first post涵盖了使用任何 google apis的基本要求: authentication (“ authn”)和授权(“ authz”)。通过拥有带有适当申请credentialsdeveloper projectcredentialscredentials

second post概述了使用Google API的下一步:选择开发语言和API,使用适当的客户端库,并在DevConsole中启用所选的API。对于编程语言,我选择了 python node.js ,然后选择了Google Drive API来制作一个简单的脚本,该脚本将Google Drive中的前100个文件/文件夹丢弃。启用驱动器API并安装客户端库后,您就可以编码。

我对这篇第三次也是最长的帖子感到兴奋,这不仅是因为它完成了三部分系列,而且因为我终于可以显示一些代码!虽然我对Python最舒服,但我也在学习节点,因此我很高兴能够以两种语言来演示“相同”脚本。但是,让我们先从python开始。

Python

下一部分描述了Python脚本的主要部分。该代码在http://g.co/codelabs/gsuite-apis-intro的CodeLab中更详细地描述,但是,它基于较旧的Python auth库,而所有Drive API documentation都已切换到了较新的库。无论如何,这篇文章给您足够的信息,以了解脚本koude0如何工作。

进口

from __future__ import print_function
import os.path

from google.auth.transport.requests import Request
from google.oauth2 import credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient import discovery

标准库import首先出现,__future__.print_function通过将python 3 print()函数带入Python 2应用程序,从而启用Python 2-3兼容性。 (在Python 3中忽略了此导入。

下一个块导入与GWS API交谈所需的所有软件包,包括Google APIS客户端库(googleapiclient)和所需的安全库。

安全

代码段

creds = None
SCOPES = 'https://www.googleapis.com/auth/drive.metadata.readonly'
TOKENS = 'storage.json'
if os.path.exists(TOKENS):
    creds = credentials.Credentials.from_authorized_user_file(TOKENS)

if not (creds and creds.valid):
    if creds and creds.expired and creds.refresh_token:
        creds.refresh(Request())
    else:
        flow = InstalledAppFlow.from_client_secrets_file(
                'client_secret.json', SCOPES)
        creds = flow.run_local_server()

with open(TOKENS, 'w') as token:
    token.write(creds.to_json())

许可范围

SCOPES代表应用程序将从最终用户请求的权限;它是单个字符串或一系列此类字符串(Python list)。在这种情况下,这是一个代表Google驱动器元数据读取权限范围的字符串。虽然它看起来像一个URL,但它被翻译为浏览器或计算机语言环境指定的语言的句子。在英语中,它将是:“请参阅有关您的Google Drive文件的信息。” 有关您自己的应用程序,范围将根据其使用的GWS API而有所不同。

例如,我还有另一个脚本可以访问驱动器和表API以及Google Cloud(GCP)存储和视觉API(请参阅this blog post),其中sample app的范围看起来像这样:

SCOPES = (
    'https://www.googleapis.com/auth/drive.readonly',
    'https://www.googleapis.com/auth/devstorage.full_control',
    'https://www.googleapis.com/auth/cloud-vision',
    'https://www.googleapis.com/auth/spreadsheets',
)

在此示例中,驱动器范围请求略有不同:是的,它也是仅读取的,但是该范围不是文件元数据,而不是文件元数据,而是访问文件 content 的权限。对于GC和表格,两个范围都是读写的,而Cloud Vision API仅处理数据(不读取或编写个人数据)。

Oauth流动

上一篇文章指示您在创建OAuth客户端ID(和SECRET)之后下载JSON凭据文件,将其保存在本地文件系统中,为client_secret.json。连接到Google服务器请求API访问时,将与脚本所请求的范围一起介绍它们(InstalledAppFlow.from_client_secrets_file())。一旦用户允许访问权限,OAuth Tokens(creds)将被发送回并存储在本地代币存储文件(TOKENS)中。这些OAuth代币是访问Google API所需的,并且它们在本地加缓存,因此每次执行脚本时都不会提示用户。

有一对oauth令牌(访问令牌刷新令牌):访问令牌提供API访问,但在刷新令牌不过期的情况下到期(但是可以被撤销)。如果访问令牌已过期,则使用刷新令牌请求新的(非预期)访问令牌。有关整个流程的更多信息可以在Google's documentation中找到。

刚才描述的都是如何工作的,但这是您在脚本中看到的:

  1. 检查现有的令牌存储文件,如果是,请加载其内容
  2. 检查是否存在凭据(两个oauth2令牌)并且有效
  3. 如果存在凭据但已过期,请使用刷新令牌请求另一个有效(访问)令牌
  4. 如果不存在凭据,请创建“ oauth flow”并渲染到authz的最终用户
  5. 不管如何获得凭据,(重新)保存最新令牌(最后几行)

应用

DRIVE = discovery.build('drive', 'v3', credentials=creds)
files = DRIVE.files().list().execute().get('files', [])
for f in files:  # 4 fields returned: mimeType, kind, id, name
    print(f['name'], f['mimeType'])

有趣的故事:实际应用程序所占用的代码线少于实现上述必要的安全性。第一行为Google Drive API创建了一个终点(V3是当前版本)。将其视为“ API客户端”。第二行从可通过API获得的方法收集的files()收集中调用list(),并返回文件列表。然后将文件用文件名和模拟型显示。如果在用户的Google驱动器中找不到文件/文件夹,则分配一个空数组(list),没有显示任何内容。

就是这样,在这里没有其他代码行。该脚本及其较旧的Auth库等效(koude14)在Codelab中的特征可以在https://github.com/wescpy/gsuite-apis-intro的仓库中的python文件夹中找到。现在让我们看一下节点版本。

node.js/javascript

脚本的node.js版本是文件,koude16

进口

const fs = require('fs').promises;
const path = require('path');
const process = require('process');
const {authenticate} = require('@google-cloud/local-auth');
const {google} = require('googleapis');

标准node.js文件系统(fs),filepath(path)和process软件包与Google Auth和API客户端库一起导入。如果您喜欢ES模块样式,以下是您在koude21中找到的等效import语句:

import fs from 'node:fs/promises';
import path from 'node:path';
import process from 'node:process';
import {authenticate} from '@google-cloud/local-auth';
import {google} from 'googleapis';

下面的其余代码在两个JavaScript版本中都是相同的。

安全

等效的JavaScript安全代码与Python版本完全一样。唯一的区别是,安全步骤被分解为其自己的async函数,因此还有更多代码可以查看:

async function loadSavedCredentialsIfExist() {
  try {
    const content = await fs.readFile(TOKEN_PATH);
    const credentials = JSON.parse(content);
    return google.auth.fromJSON(credentials);
  } catch (err) {
    return null;
  }
}

async function saveCredentials(client) {
  const content = await fs.readFile(CREDENTIALS_PATH);
  const keys = JSON.parse(content);
  const key = keys.installed || keys.web;
  const payload = JSON.stringify({
    type: 'authorized_user',
    client_id: key.client_id,
    client_secret: key.client_secret,
    refresh_token: client.credentials.refresh_token,
    access_token: client.credentials.access_token,
  });
  await fs.writeFile(TOKEN_PATH, payload);
}

async function authorize() {
  var client = await loadSavedCredentialsIfExist();
  if (client) return client;
  client = await authenticate({
    scopes: SCOPES,
    keyfilePath: CREDENTIALS_PATH,
  });
  if (client.credentials) await saveCredentials(client);
  return client;
}

典型的用法模式是对authorize()的呼叫,请按照您要运行的代码(在我们的情况下解决承诺后),在我们的情况下通过下面显示的listFiles()函数进行实际应用程序。

应用

async function listFiles(authClient) {
  const drive = google.drive({version: 'v3', auth: authClient});
  const res = await drive.files.list();
  const files = res.data.files || [];
  for (let file of files) {
    console.log(`${file.name} (${file.mimeType})`);
  }
}

authorize().then(listFiles).catch(console.error);

像Python版本一样,listFiles()创建一个驱动器API客户端并调用其files.list()方法。只要返回至少一个文件/文件夹,就会显示文件名和模仿。脚本中的最后一行包括“主”应用程序,称为authorize()以获取传递给listFiles()的凭据。就是这样,您在这里看不到其他代码行。这两个脚本都可以在https://github.com/wescpy/gsuite-apis-intro的Repo的nodejs文件夹中找到。

打字稿注释

,由于JSONClientOAuth2Client类型之间的冲突,您将其中一些移植到打字稿可能会遇到一些挑战。具体来说,此错误可能会显示:error TS2322: Type 'OAuth2Client' is not assignable to type 'JSONClient'. Type 'OAuth2Client' is missing the following properties from type 'Impersonated': sourceClient, targetPrincipal, targetScopes, delegates, and 3 more.我发现触摸此主题的唯一线索是在此closed bug on GH中。如果您能够获得工作版本,请在下面给我发表评论,我将更新此帖子。

运行脚本

现在编码完成了,是时候通过执行脚本来获得奖励了。执行有两个阶段。首先是通过安全过程。完成后,代码将运行。如果执行之间未发生权限更改,则安全流只能在初始执行时发生一次。之后,Oauth令牌是“自我管理:”

  1. 如果访问令牌仍然有效,则执行为正常
  2. 如果访问令已过期,则用于请求新访问令牌的刷新令牌;执行收益

无论如何,这些步骤并没有暴露于只有一次初始权限的最终用户。让我们看看这些步骤在实践中的外观。

Authn和Authz

第一次执行脚本时,用户Muse authenticate (登录或选择签署的Google帐户),然后授权该应用程序,授予它请求的许可。对于当时的Authn部分,您将获得一个Google帐户 - 选择器,可以从中选择您要使用的一个,看起来像这样:

Google account-chooser

[图像] Google帐户选择器

选择所需的帐户后,您可能会得到一个“ Google has has has n verne this应用” 屏幕:

Google unverified app dialog

[图像] Google未经验证的应用程序对话框

虽然看起来有些担心,但其目的是让用户知道Google尚未验证此应用程序,该应用程序将要求使用权限访问您的数据。这一切都是为了保护最终用户。现在没有什么可担心的,因为它是您的代码,您只会使用它访问自己的数据。在Google's unverified apps support page中了解有关此通知的更多信息。

单击高级在底部的链接,如果您了解风险:

Google unverified app dialog, advanced section

[图像]未经验证的应用程序对话框,高级部分

由于您是开发人员,希望您能够相信自己足够的继续进行。如果是这样,请单击“转到 your-app-name (不安全)” 链接(其中 your-app-name 是您的在前面的OAuth同意屏幕中配置)。这将带您到期待已久的OAuth2 authz Flow对话框:

OAuth2 authorization dialog

[image] OAuth2授权对话框

在这里,提示最终用户向开发人员提供请求的许可以访问其私人数据。出于此演示的目的,您是最终用户,数据所有者以及开发人员。基本上,您将访问脚本对驱动器文件的访问。

单击继续时,安全流完成,您的代码将执行。如果用户单击取消而不是返回OAuth令牌,并且脚本失败;这就是设计。底线是,由于这是私人用户数据,因此在发生API访问之前必须授予所有者许可

要查看Authn&Authz之间的差异或了解有关此安全流的更多信息,请在GWS文档中查看Part 1 post以及this security overview page

脚本执行

最终用户选择输入后,脚本的执行开始。 listFiles()方法返回最终用户的Google Drive中的前100个文件/文件夹,因此在运行应用程序时,期望看到其名称和模拟物。您的输出肯定会有所不同,但是下面是我最初为post on my old blog制作此脚本的Google Drive的一些示例输出:

$ python3 drive_list-new.py  # or $ node drive_list.js
Google Maps demo application/vnd.google-apps.spreadsheet
Overview of Google APIs - Sep 2014 application/vnd.google-apps.presentation
tiresResearch.xls application/vnd.google-apps.spreadsheet
6451_Core_Python_Schedule.doc application/vnd.google-apps.document
out1.txt application/vnd.google-apps.document
tiresResearch.xls application/vnd.ms-excel
6451_Core_Python_Schedule.doc application/msword
out1.txt text/plain
Maps and Sheets demo application/vnd.google-apps.spreadsheet
ProtoRPC Getting Started Guide application/vnd.google-apps.document
gtaskqueue-1.0.2_public.tar.gz application/x-gzip
Pull Queues application/vnd.google-apps.folder
gtaskqueue-1.0.1_public.tar.gz application/x-gzip
appengine-java-sdk.zip application/zip
taskqueue.py text/x-python-script
Google Apps Security Whitepaper 06/10/2010.pdf application/pdf

它不是很漂亮,我的示例驱动器文件夹甚至没有100个文件/文件夹,但它只是概念验证,而不是很浮华。令人兴奋的是,您看到了您识别的文件名,并且它们出现在命令行上,远离您的Web浏览器和驱动器用户界面。

对于那些喜欢更多视觉内容的人来说,下面是我几年前制作的视频,涵盖了这篇文章中的大部分内容并演示了相同的(Python)应用程序。某些代码或视频屏幕截图可能已更新,但核心功能大多相同。

[视频]列出了Google Drive中的第一个100个文件/文件夹

命令行脚本与Web或移动应用程序

命令行脚本将不是最广泛实现的应用程序类型。您更有可能将GWS API使用添加到Web或移动应用程序中。呼叫会有所不同,但是OAuth流相似。 Google的文档中有一个特定页面,用于managing the OAuth flow process for web apps以及one for mobile apps

概括

这个三部分博客文章系列的目的是从一无所有开始,并使用GWS API(例如Google Drive)将开发人员带入一个完全有效的命令行脚本。 GWS产品的API使用OAuth客户端ID作为AUTHZ机制。现在您已经完成了此“ Hello World”应用程序,这取决于您现在可以做的事情的想象...扩展驱动器API使用情况,与其他GWS API连接,例如文档,表,幻灯片,幻灯片,表单,日历或gmail。

在即将发布的帖子中,我将查看其他使用不同类型的AUTHZ机制的Google API系列,即 api键(MAP)和服务帐户(GCP) 。请继续关注Authn和API客户端库的其他帖子。如果python或node.js“是您的事”,您还会在Java,GO和客户端JavaScript中找到Google Drive API QuickStart(请参阅Left-Nav)。最后,如果您对您想听到的内容有想法或如何改善node.js(或python)代码,请在下面发表评论!

参考



Wesley Chun ,MSCS,是Prentice Hall的畅销书 Core Python 系列的作者, Python Web Development with Django 的合着者,并为Linux Journal&CNET写了。他运行CyberWeb专门从事Python,Google Cloud和Google Workspace(Gmail,Dri​​ve,文档,床单,幻灯片,幻灯片,应用程序脚本等)的技术培训和咨询。他是最初的Yahoo!邮件工程师之一,并在各种Google API产品团队上度过了13年以上,包括生产Serverless Migration StationWorkspace/G Suite Dev Show视频系列。韦斯利(Wesley)拥有加利福尼亚大学的计算机科学,数学和音乐学位,是Python Software Foundation的院士,喜欢旅行,与会议,用户团体活动和大学的全球开发人员见面。在Twitter @wescpyStackOverflowGitHub上关注他/他。发现此内容有用吗? Buy him a coffee (or tea)!