使用 Google Drive API + Parse 将文件存储在单个 Drive 帐户上

我正在尝试将单个 Google Drive 帐户用作网络服务器".我有一个需要能够存储和检索图片的 Android 应用程序.我的想法是使用 Parse 来帮助管理所有内容并将我的存储容量扩展到 Parse 的可用容量之外.

I am trying to use a single Google Drive account as a 'web server.' I have an Android app that needs to be able to store and retrieve pictures. My idea was to use Parse to help manage everything and extend my storage capacity beyond Parse's free amount.

基本上,我将拥有一个 Google Drive 帐户和一个 Parse 项目.当用户想要存储文件时,他/她将文件上传到 Parse,Parse 使用单个 Google Drive 帐户(使用 CloudCode)进行身份验证,Parse 将文件上传到 Drive,将文件的 URL 存储在表中,然后删除Parse 的云存储中的文件.我计划为存储这些文件的文件夹提供私有写入访问权限和公共读取访问权限,这样客户端就不必发出 Parse 请求

Essentially, I will have a single Google Drive account and a Parse project. When a user wants to store a file, he/she uploads the file to Parse, Parse authenticates with the single Google Drive account (using CloudCode), Parse uploads the files to Drive, stores the URL to the file in a table, and deletes the file from Parse's cloud storage. I plan on giving the folder that stores these files private write access and public read access so the clients don't have to make Parse requests to

这样做的目的是为我的应用程序获得更多存储空间.(Amazon S3 只提供 5g,Parse 提供 1g,DropBox 2g,Google Cloud Storage 我不认为他们有免费计划,Drive 提供 15g 但我也听说过 Google Photos 与 Google Drive 集成,这可能会给我无限的存储空间图片)

The purpose of this is to get more storage for my application. (Amazon S3 only gives 5g, Parse gives 1g, DropBox 2g, Google Cloud Storage I don't think they have a free plan, and Drive gives 15g but I have also heard about Google Photos integrating with Google Drive which might give me unlimited storage for pictures)

由于 Google 云端硬盘并非真正设计用于执行此操作,因此我很难弄清楚所有部分是如何组合在一起的.

Because Google Drive wasn't really designed to do this, I am having some difficultly figuring out how all the pieces fit together.

我看过这个 问题 似乎不适用于我的情况,因为我将能够在安全服务器上运行所有写操作.(我也读过我需要存储一个刷新令牌,使用这种方法也应该是安全的)

I have looked at this question which doesn't seem to apply to my situation because I will be able to run all my write operations on a secure sever. (Also I have read I need to store a refresh token which should also be secure using this method)

我查看了 this 但许多链接都已过时,所以没有对我帮助不大.

I have looked at this but many of the links are outdated, so that didn't help me much.

我查看了 this,但这似乎是在授权应用程序的使用用户的个人文件.

I have looked at this, but this seems to be authorizing an app's use of the user's personal files.

我还读到如果使用 Web 应用程序帐户,我可能需要使用服务帐户,但同样,我一直在阅读的信息不是很清楚.在我看来,这是因为云端硬盘的设计初衷并非如此.

I have also read that I may need to use a service account instead if a Web Application account, but again, the information I have been reading has not been very clear. In my opinion, this is because Drive was not designed to work this way.

总结:

谁能指出我使用 Parse Cloud Code(服务器端 Javascript)将文件写入单个 Google Drive 帐户的正确方向?

如果上述问题可以解决/可能,Google 发布 Google Photo 是否意味着我将拥有基本上无限的图片存储容量?

推荐答案

好的.因此,经过数小时的研究和测试,我想出了一种让它发挥作用的方法.

OK. So after hours of research and testing, I have come up with a way of getting this to work.

Google 的 API 身份验证过程至少可以说有点令人困惑.一般流程如下:

Google's API authentication process is a bit confusing to say the least. The general procedure is as follows:

  1. 要求用户授予对 INSERT YOUR PROJECT HERE 范围 YOUR SCOPE
  2. 的访问权限
  3. 用户可以接受或拒绝该请求
  4. 如果用户接受,您可以检索访问令牌(更重要的是刷新令牌)
  5. 获得刷新令牌后,您可以获得新的访问令牌,以便随时进行 API 调用.

所以整个目标是进行需要刷新代码的 API 调用(特别是驱动).

So the whole goal of this is to make API calls (specifically to drive) which requires a refresh code.

这方面的主要困难是(据我所知)无法在 Parse CloudCode 中验证用户并获取访问代码.但是,我有一个理论,如果我能够以某种方式在 CloudCode 之外验证用户帐户,您仍然可以制作 GET/POST 来自 CloudCode 函数内部的请求.(更具体地说:Parse.Cloud.httpRequest)

The main difficulty in this is, (AS FAR AS I KNOW) there is no way of authenticating a user and getting an access code inside of Parse CloudCode. BUT, I had a theory that if I was somehow able to authenticate the user account outside of CloudCode, you could still make GET/POST requests from inside a CloudCode function. (More specifically: Parse.Cloud.httpRequest)

有许多方法/平台可让您对用户进行身份验证以获取刷新代码.最容易使用的方法可能是使用 API 的 Android/Java 版本,因为任何有计算机的人都可以运行 Android 模拟器,但我可以轻松访问支持 PHP 的网站,所以我选择使用 PHP.但同样,这部分过程可以在许多不同的平台上完成.

There are many ways/platforms that allow you to authenticate a user in order to get a refresh code. The most accessible method would probably be by using the Android/Java version of the API because anyone with a computer can run an Android emulator, but I have easy access to a PHP capable website, so I chose to use PHP instead. But again, this part of the process can be done on many different platforms.

第一步是安装 Google API Client Library for PHP (Github).有几种不同的方法可以在您的服务器上安装它,但由于我只需要它来获取刷新令牌,因此我选择在运行时动态包含它(也是因为我无法快速访问我的 php.ini 文件).ini 文件).

The first step is to install the Google API Client Library for PHP (Github). There are a few different ways to install this on your server, but since I only need it to get a refresh token, I chose to include it dynamically at runtime (also because I didn't have quick access to my php.ini file).

(在我继续之前请注意:我不是 PHP 开发人员,所以如果我做了任何奇怪或多余的事情,请告诉我;我只是展示了我为使其工作所做的工作)

(Note before I continue: I am not a PHP developer, so please let me know if I do anything odd or redundant; I am merely showing what I did to get this to work)

为此,我只需下载该库的副本,将其上传到我的服务器,并在我使用该库的所有文件中包含以下行:

To do this I simply downloaded a copy of the library, uploaded it to my server, and included the following line in all the files I used the library:

set_include_path(get_include_path() . PATH_SEPARATOR . 'google-api-php-client-master/src');

其中 google-api-php-client-master/src 是您的 src 文件夹的路径.

Where google-api-php-client-master/src is the path to your src folder.

完成后,您必须对用户进行身份验证.以下两个文件将用户发送到身份验证页面,然后在屏幕上打印该用户的刷新代码.

Once you have that done, you have to authenticate the user. The following two files send the user to an authentication page, and then print the refresh code for that user on the screen.

index.php:

<?php
    set_include_path(get_include_path() . PATH_SEPARATOR . 'google-api-php-client-master/src');
    require_once 'google-api-php-client-master/src/Google/autoload.php'; // or wherever autoload.php is located 

    session_start();

    $client = new Google_Client();
    $client->setAuthConfigFile('client_secrets.json'); //You can download this file from your developer console under OAuth 2.0 client IDs
    $client->addScope(Google_Service_Drive::DRIVE); //Scope that grants full access to user's Google Drive
    $client->setAccessType("offline"); //Important so a refresh code is returned

    if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
        print($_SESSION['refresh_token']);
    } else {
        $redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php';
        header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
    }
?>

oauth2callback.php:

<?php

    set_include_path(get_include_path() . PATH_SEPARATOR . 'google-api-php-client-master/src');

    require_once 'google-api-php-client-master/src/Google/autoload.php';

    session_start();

    $client = new Google_Client();
    $client->setAuthConfigFile('client_secrets.json');
    $client->setRedirectUri('http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php');
    $client->addScope(Google_Service_Drive::DRIVE);
    $client->setAccessType("offline");

    if (! isset($_GET['code'])) {
      $auth_url = $client->createAuthUrl();
      header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
    } else {
      $client->authenticate($_GET['code']);
      $_SESSION['access_token'] = $client->getAccessToken();
      $_SESSION['refresh_token'] = $client->getRefreshToken(); //Important to clear the session variable after you have the token saved somewhere
      $redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/'; //Redirects to index.php
      header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
    }

?>

关于此代码的几个重要说明:

Several important notes about this code:

  1. 您需要确保您已创建适当的凭据(网络应用程序)
  2. 您需要将正确的重定向 URI 添加到您的 OAuth 2.0 客户端 ID.它应该类似于 http://yourdomain.com/oauth2callback.php.
  3. 您需要将 client_secrets.json 文件上传到您的服务器.您可以通过转到开发人员控制台并单击 OAuth 2.0 客户端 ID 列表最右侧的下载图标来获取此信息.
  4. 出于安全原因,您可能应该在复制刷新令牌后清除会话变量.
  1. You need to make sure you have created the appropriate credentials (Web application)
  2. You need to add the correct redirect URI to your OAuth 2.0 client ID. It should be something like http://yourdomain.com/oauth2callback.php.
  3. You need to have uploaded your client_secrets.json file to your server. You can get this by going to your developers console and clicking the download icon on the far right side of the OAuth 2.0 client IDs list.
  4. You should probably clear your session variables after you copy the refresh token down for security reasons.

因此,总而言之,我们创建了一个简单的程序,可以为特定用户打印出刷新令牌.您需要将该代码复制下来并保存以备后用.

So in summary, we have created a simple program that prints out the refresh token for a specific user. You need to copy that code down and save it for later.

即使您拥有刷新令牌,您也需要一种获取访问令牌以进行 API 调用的方法.(如果没有访问令牌,您无法进行 API 调用,而且由于它们每 3600 秒过期一次,因此您需要一种在需要时获取新令牌的方法)

Even though you have the refresh token, you need a way of getting an access token to make API calls. (You can't make an API call without an access token, and because they expire every 3600 seconds, you need a way of getting a new one when you need it)

这是完成此步骤的 Parse CloudCode:

Here is the Parse CloudCode for accomplishing this step:

Parse.Cloud.define("getAccessToken", function(request, response) {
    Parse.Cloud.httpRequest({
        method: "POST",
        url: 'https://www.googleapis.com/oauth2/v3/token/',
        params: {
            refresh_token : 'INSERT_REFRESH_TOKEN_HERE',
            client_id : 'INSERT_CLIENT_ID_HERE',
            client_secret : 'INSERT_CLIENT_SECRET_HERE',
            grant_type : 'refresh_token'
        }
    }).then(function(httpResponse) {
      response.success(httpResponse.text);
    }, function(httpResponse) {
      response.error('Request failed with response code ' + httpResponse.status);
    });
});

这个函数发送一个访问令牌的请求.你可以用那个令牌做任何你想做的事;它存储在 httpResponse.text 中(如果请求成功).请注意,grant_type 应该是 refresh_token 而不是您的刷新令牌.

This function sends a request for an access token. You can do whatever you want with that token; it is stored in httpResponse.text (if the request was successful). Note that grant_type should be refresh_token not YOUR refresh token.

获得访问令牌后,您就可以在刷新令牌范围内自由地进行 API 调用.示例:

Once you have an access token, you are free to make API calls within the scope of your refresh token. Example:

Parse.Cloud.define("sendRequest", function(request, response) {
    Parse.Cloud.httpRequest({
        method: "GET",
        url: 'https://www.googleapis.com/drive/v2/about',
        params: {
            access_token : 'INSERT_YOUR_ACCESS_TOKEN_HERE'
        }
    }).then(function(httpResponse) {
      response.success(httpResponse.text);
    }, function(httpResponse) {
      response.error('Request failed with response code ' + httpResponse.status);
    });
});

此函数返回有关与该刷新令牌关联的驱动器帐户的信息.

This function returns information about the drive account associated with that refresh token.

关于我的第二个问题,我还没有做足够的研究来知道答案,但我计划找出并在这里发布.

With regards to my second question, I have not done enough research to know the answer to that yet, but I plan on finding out and posting it here.

相关文章