如何使用 API 密钥从 PHP 通过 google/apiclient 驱动 Google 驱动器 API

How to use the API Key for Google Drive API from PHP via the google/apiclient

我希望我的 PHP 网络应用程序在特定的 google 帐户(不是任意用户的帐户,而是我们公司的特定帐户)中创建电子表格。

我测试过并且确实有效的方法

我需要 google/apiclient PHP 客户端库。它已经起来 运行.

我的控制器中有那些私有方法:

private function getGoogleDriveService( string $scopes ) : \Google_Service_Drive
{
    $client = $this->getClient( $scopes );

    $service = new \Google_Service_Drive( $client );

    return $service;
}

private function getClient( string $scopes ) : \Google_Client
{
    $client = new \Google_Client();

    $client->setApplicationName( 'My nice application name.' );
    $client->setAuthConfig( $this->getSecretPath() );
    $client->setScopes( $scopes );
    $client->setAccessType( 'offline' );

    return $client;
}

private function getSecretPath() : string
{
    $projectDir = $this->get( 'kernel' )->getProjectDir();
    $credentialsFullPath = $projectDir . '/app/config/googleApiSecret.json';

    return $credentialsFullPath;
}

我调用 getGoogleDriveService 告诉我想要的特定控制器操作的范围,以创建 Google 服务。该服务首先通过调用 getClient 来创建,其中 returns 是一个已初始化的 \Google_Client 对象,后者又将 credentials.json 路径传递给它。

到目前为止,还不错。这行得通。

例如使用这样的代码:

$driveService = $this->getGoogleDriveService( \Google_Service_Drive::DRIVE );

$file = new \Google_Service_Drive_DriveFile();
$file->setName( 'My nice dummy file' );
$file->setMimeType( 'application/vnd.google-apps.spreadsheet' );
$file = $driveService->files->create( $file );

$feedbackMessage = sprintf( 'Created spreadsheet via DRIVE API with Id: %s', $file->id );

但是手残!!这是作为 "Service Account" 工作的。它在某种 "secret" 的地方创建和修改文件,这在云端硬盘 Web 前端是不可见的。

会发生什么

我有一个用户(例如 alice@gmail.com),这个用户就是创建 "Service account" 的用户。凭据文件包含某种 "ficticious email address" 或多或少类似的内容:alice@my-nice-super-project.iam.gserviceaccount.com

.json 大致是这样的:

{
  "type": "service_account",
  "project_id": "my-nice-super-project",
  "private_key_id": "7777777777777788888888888888899999999999",
  "private_key": "-----BEGIN PRIVATE KEY-----\nxxx[...]xxx==\n-----END PRIVATE KEY-----\n",
  "client_email": "alice@my-nice-super-project.iam.gserviceaccount.com",
  "client_id": "123456789123456789123",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://accounts.google.com/o/oauth2/token",
  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
  "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/alice%40my-nice-super-project.iam.gserviceaccount.com"
}

发生的事情是:

  1. 如果我使用 alice@gmail.com 登录到 google 驱动器(使用浏览器)并手动创建电子表格文件 Hello-1 然后我无法从应用程序中读取它。
  2. 如果我从登录为 alice@gmail.com 的网站手动共享文件 Hello-1 并将其共享到 alice@my-nice-super-project.iam.gserviceaccount.com,那么我可以从应用程序读取文件。但是我无法从应用程序中删除它。
  3. 如果我从应用程序创建文件 Hello-2,它在 alice@gmail.com 网络前端是不可见的。

似乎即使服务帐户是从 alice@gmail.com 创建的,它也作为一个完全独立的存储工作,来自 "human Alice" 和 "robot Alice" 的文件被视为来自不同的存储用户。

我需要什么

我想要的是应用程序可以 read/write alice@gmail.com 的文件而不提示 OAuth 权限。

所以,要明确一点:我不希望我的 PHP 网络应用程序能够 "edit anyone's Drive with his consent",但我想要的是 "anyone can edit Alice's Drive".

背后的原因是我们已经拥有了爱丽丝账户,它就像一些文件的"central storage"。

公司中的多个代理必须能够通过应用程序编辑内容,只有老板才能通过 Google Drive 站点登录。代理没有 Alice 密码,因此他们无法通过 OAuth 同意。但该公司拥有 Alice 帐户,因此我们可以进入那里并创建 API 密钥,并将它们设置在服务器中。

我卡在哪里

我可以通过服务帐户设法使软件运行。但这不是我想要的:我希望该软件能够运行 "on Alice's documents",而不是在 "Alice Service Account's documents" 上运行,因为它们似乎生活在不同的世界中。

我不知道如何初始化

$service = new \Google_Service_Drive( $client );

所以它可以在没有 OAuth 同意的情况下使用 Alice 的文件。

当您使用服务帐户并且您有G Suite Account, you can use Domain-Wide Delegation of Authority ,这样您的服务帐户 alice@my-nice-super-project.iam.gserviceaccount.com 将能够模拟您想要的任何用户,在本例中是您的 alice@gmail.com.

这将帮助您使用已有的代码在 alice@gmail.com 驱动器中创建文件。您只需要修改这部分代码:

private function getClient( string $scopes ) : \Google_Client
{
    // Add this line of code
    // User you want to "impersonate"
    $user = "alice@gmail.com"

    $client = new \Google_Client();

    $client->setApplicationName( 'My nice application name.' );
    $client->setAuthConfig( $this->getSecretPath() );
    $client->setScopes( $scopes );
    $client->setAccessType( 'offline' );
   // Add this line of code
   $client->setSubject( $user );

    return $client;
}

HERE 您可以查看有关 PHP.

的 Google API 客户端库的更多信息
  • 您想使用服务帐户写入和读取 alice@gmail.com 的 Google 驱动器中的文件。
  • 您想使用服务帐户写入和读取 alice@gmail.com 的文件。
  • 您想用浏览器查看文件。

为了实现上述情况,我想提出以下方法。请将此视为几个可能的答案之一。

方法:

  1. alice@gmail.com 的驱动器中创建一个文件夹并与服务帐户共享该文件夹。
  2. 当使用服务帐户的应用程序在共享文件夹中创建新文件时,将文件的所有者更改为alice@gmail.com并与服务帐户共享。

通过以上方法,应用程序可以写入和读取alice@gmail.com的文件,并且alice@gmail.com可以通过浏览器查看自己帐户中的文件。

注:

  • alice@gmail.com的Drive与服务账号的Drive不同。并且浏览器无法直接看到服务帐户的Drive。所以在这个方法中,使用了share。

参考: