【问题标题】:Insufficient Permission when trying to create a folder on Google Drive via API(v3)尝试通过 API(v3)在 Google Drive 上创建文件夹时权限不足
【发布时间】:2018-08-18 15:30:56
【问题描述】:

我正在尝试通过 API 在我的 Google Drive 上创建一个文件夹。我正在使用 Node,并创建了一个脚本来获取每日报告,并希望通过 API 创建一个文件夹并将这些文件每天上传到它。

为了进行设置,我根据文档的quick start guide 创建了一个项目。我的设置看起来与样板基本相同,但减去了读取 Drive 中文件的功能。但是,在尝试上传 using the example given in the docs 时出现错误:Insufficient Permission

通过项目界面中的权限,有一堆角色可供选择。目前,我已将我的项目分配为文件夹管理员(以及其他几个角色),应该授予我权限,但我仍然遇到此错误。也许我需要重新生成我的client_secret.json 文件以反映我更新的权限,但我该怎么做呢?我一直在谷歌搜索和浏览界面很长一段时间,但看不到重新生成此文件的方法。

我用来创建文件夹的代码看起来像这样,非常接近文档中给出的样板 - 只是为了看看它是否有效:

const drive = google.drive('v3')    
function createFolder (auth) {
      console.log('auth:', auth)
      const fileMetadata = {
        'name': 'daily-report',
        'mimeType': 'application/vnd.google-apps.folder',
        'parents': ['1P924MEzU_1VoL6OOvWPHSo6vb1u9u0a9'],
      }

      drive.files.create({
        auth: auth,
        resource: fileMetadata,
        fields: 'id'
      }, function (err, file) {
        if (err) {
          // Handle error
          console.error(err.message);
        } else {
          console.log('Folder Id: ', file.id);
        }
      });
    }

感谢任何帮助。

更新错误:

    Token stored to /Users/sg/.credentials/
auth: OAuth2Client {
  transporter: DefaultTransporter {},
  _certificateCache: null,
  _certificateExpiry: null,
  _clientId: 'clientID093420402349.apps.googleusercontent.com',
  _clientSecret: 'totalsecret',
  _redirectUri: 'urn:ietf:wg:oauth:2.0:oob',
  _opts: {},
  credentials: 
   { access_token: 'xxxxxxxxxxxx',
     refresh_token: 'xxxxxxxxxxxx',
     token_type: 'Bearer',
     expiry_date: 1520651774212 } }
(node:76284) [DEP0013] DeprecationWarning: Calling an asynchronous function without callback is deprecated.
fs.js:106
        throw backtrace;
        ^

Error: EISDIR: illegal operation on a directory, open '/Users/sg/.credentials/'
    at rethrow (fs.js:101:21)
    at maybeCallback (fs.js:119:42)
    at Object.fs.writeFile (fs.js:1260:14)
    at storeToken (/Users/sg/R2-DS/src/middleware/aptlist-report-auth.js:104:6)
    at /Users/sg/R2-DS/src/middleware/aptlist-report-auth.js:85:7
    at /Users/sg/R2-DS/node_modules/google-auth-library/lib/auth/oauth2client.js:95:13
    at Request._callback (/Users/sg/R2-DS/node_modules/google-auth-library/lib/transporters.js:113:17)
    at Request.self.callback (/Users/sg/R2-DS/node_modules/request/request.js:186:22)
    at emitTwo (events.js:126:13)
    at Request.emit (events.js:214:7)

【问题讨论】:

    标签: node.js google-api google-drive-api


    【解决方案1】:

    我认为您的脚本有效。那么您能否再次确认以下几点?

    1. 关于范围。
      • 在快速入门中,默认范围是 var SCOPES = ['https://www.googleapis.com/auth/drive.metadata.readonly'];。但是为了使用drive.files.create,需要将https://www.googleapis.com/auth/drive添加到作用域中。
      • 如果您修改了范围,请删除drive-nodejs-quickstart.json 的文件。并运行脚本。这样,授权就会运行,并且添加的范围会反映到刷新令牌和访问令牌中。
    2. 关于googleapis的版本
      • 最近有报道称,v27.0.0、v26.0.1、v25.0.0的googleapis存在一些bug。因此,请确认您的版本以防万一。我使用 v24.0.0。
    3. 是否在 API 控制台启用了 Drive API。
      • 关于这个,我认为从你的问题来看,你可能已经启用了。

    如果这些对你没有用,我很抱歉。

    编辑:

    var fs = require('fs');
    var readline = require('readline');
    var google = require('googleapis');
    var googleAuth = require('google-auth-library');
    
    // If modifying these scopes, delete your previously saved credentials
    // at ~/.credentials/drive-nodejs-quickstart.json
    var SCOPES = ['https://www.googleapis.com/auth/drive'];
    var TOKEN_DIR = './';
    var TOKEN_PATH = 'drive-nodejs-quickstart.json';
    
    // Load client secrets from a local file.
    fs.readFile('client_secret.json', function processClientSecrets(err, content) {
      if (err) {
        console.log('Error loading client secret file: ' + err);
        return;
      }
      // Authorize a client with the loaded credentials, then call the
      // Drive API.
      authorize(JSON.parse(content), createFolder);
    });
    
    /**
     * Create an OAuth2 client with the given credentials, and then execute the
     * given callback function.
     *
     * @param {Object} credentials The authorization client credentials.
     * @param {function} callback The callback to call with the authorized client.
     */
    function authorize(credentials, callback) {
      var clientSecret = credentials.installed.client_secret;
      var clientId = credentials.installed.client_id;
      var redirectUrl = credentials.installed.redirect_uris[0];
      var auth = new googleAuth();
      var oauth2Client = new auth.OAuth2(clientId, clientSecret, redirectUrl);
    
      // Check if we have previously stored a token.
      fs.readFile(TOKEN_PATH, function(err, token) {
        if (err) {
          getNewToken(oauth2Client, callback);
        } else {
          oauth2Client.credentials = JSON.parse(token);
          callback(oauth2Client);
        }
      });
    }
    
    /**
     * Get and store new token after prompting for user authorization, and then
     * execute the given callback with the authorized OAuth2 client.
     *
     * @param {google.auth.OAuth2} oauth2Client The OAuth2 client to get token for.
     * @param {getEventsCallback} callback The callback to call with the authorized
     *     client.
     */
    function getNewToken(oauth2Client, callback) {
      var authUrl = oauth2Client.generateAuthUrl({
        access_type: 'offline',
        scope: SCOPES
      });
      console.log('Authorize this app by visiting this url: ', authUrl);
      var rl = readline.createInterface({
        input: process.stdin,
        output: process.stdout
      });
      rl.question('Enter the code from that page here: ', function(code) {
        rl.close();
        oauth2Client.getToken(code, function(err, token) {
          if (err) {
            console.log('Error while trying to retrieve access token', err);
            return;
          }
          oauth2Client.credentials = token;
          storeToken(token);
          callback(oauth2Client);
        });
      });
    }
    
    /**
     * Store token to disk be used in later program executions.
     *
     * @param {Object} token The token to store to disk.
     */
    function storeToken(token) {
      fs.writeFile(TOKEN_PATH, JSON.stringify(token));
      console.log('Token stored to ' + TOKEN_PATH);
    }
    
    /**
     * Lists the names and IDs of up to 10 files.
     *
     * @param {google.auth.OAuth2} auth An authorized OAuth2 client.
     */
    function createFolder(auth) {
          const drive = google.drive('v3');
          console.log('auth:', auth);
          const fileMetadata = {
            'name': 'daily-report',
            'mimeType': 'application/vnd.google-apps.folder',
            'parents': ['1P924MEzU_1VoL6OOvWPHSo6vb1u9u0a9'],
          };
    
          drive.files.create({
            auth: auth,
            resource: fileMetadata,
            fields: 'id',
          }, function(err, file) {
            if (err) {
              // Handle error
              console.error(err.message);
            } else {
              console.log('Folder Id: ', file.id);
            }
          });
        }
    

    【讨论】:

    • 是的!谢谢!!我已经更新了范围,但不知道我需要删除 drive-nodejs-quickstart.json!!!!谢谢一百万:)
    • @HolyMoly 请尝试$ npm list --depth=0。如果您将 googleapis 安装到 gloval,请尝试$ npm list --depth=0 -g。如果您使用的是 v27.0.0、v26.0.1 和 v25.0.0,请尝试 v24.0.0。
    • @HolyMoly 我更新了我的答案。我为您的情况添加了修改后的快速入门。请将client_secret.json 放在当前工作目录中。这个修改后的脚本在当前工作目录上创建drive-nodejs-quickstart.json。请试试这个。如果这对你没有用,我很抱歉。
    • @HolyMoly 我确认在我的环境中,这个修改后的脚本适用于 googleapis v24.0.0。
    • 这成功了!我在云端硬盘中有我的文件夹!终于解脱了!哈哈哈!你太棒了!非常感谢,我已经在这几个小时发疯了,你太有耐心了,我真的太感谢你了! :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多