You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Ruby调用Google Drive API删除文件时的权限问题

问题:Google Drive文件下载后无法通过服务账号删除

我用Google Apps Script从电子表格生成JSON文件并存到Google Drive,再用Ruby脚本下载这些文件,但下载后无法删除,报错权限不足。


Google Apps Script 生成JSON文件代码

function makeJSON() {
  var spreadsheetId = 'someId'; 
  var spreadsheet = SpreadsheetApp.openById(spreadsheetId);
  var sheets = spreadsheet.getSheets();
  var urls = []; // 存储生成文件的URL

  for (var i =  1; i < sheets.length; i++) {
    var sheet = sheets[i];
    var data = sheet.getRange(3,  1, sheet.getLastRow() -  2, sheet.getLastColumn()).getValues();
    var headers = sheet.getRange(2,  1,  1, sheet.getLastColumn()).getValues()[0];

    var objects = data.map(function(row) {
    var obj = {};
    for (var j =  0; j < headers.length; j++) {
      // 数据处理逻辑
    }
    
    return obj;
    });


     // 将对象数组转为JSON字符串
    var json = JSON.stringify(objects, null,  2);
    
    // 创建JSON Blob
    var blob = Utilities.newBlob(json, 'application/json', sheet.getName() + '.json');

    var folder = DriveApp.getFolderById('someId');
    var file = folder.createFile(blob);

    file.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.EDIT); // 不想设为公开可编辑,但目前为了下载只能这么做
    
    // 获取文件ID
    var fileId = file.getId();
    
    // 构造直接下载URL
    var directDownloadUrl = "https://drive.google.com/uc?export=download&id=" + fileId;
    
    // 将URL加入数组
    urls.push(directDownloadUrl);
    
  }
  return urls;
}

function doGet() {
  var urls = makeJSON(); // 调用生成JSON文件的函数并获取URL列表
  return ContentService.createTextOutput(JSON.stringify({urls: urls})).setMimeType(ContentService.MimeType.JSON);
}

Ruby 下载脚本代码

drive_service = Google::Apis::DriveV3::DriveService.new
scope = 'https://www.googleapis.com/auth/drive'

authorizer = Google::Auth::ServiceAccountCredentials.make_creds(
  json_key_io: File.open('google_client.json'),
  scope: scope
)

authorizer.fetch_access_token!

# 为Drive API客户端设置授权
drive_service.authorization = authorizer

# 返回JSON文件URL的Web App地址
web_app_url = 'https://script.google.com/macros/s/digits/exec'

# 从Web App获取JSON数据
response = URI.open(web_app_url).read
json_data = JSON.parse(response)

# 保存文件的目录
save_directory = 'downloads'

# 确保目录存在
FileUtils.mkdir_p(save_directory) unless File.directory?(save_directory)

json_data['urls'].each do |url|
  # 从URL中提取文件ID
  file_id = url.split('id=')[1]
   
  # 通过Drive API获取文件元数据
  file_metadata = drive_service.get_file(file_id, fields: 'name')
   
  # 提取文件名
  file_name = file_metadata.name
   
  # 构造直接下载URL
  direct_download_url = "https://drive.google.com/uc?export=download&id=#{file_id}"
   
  # 构造文件保存路径
  file_path = File.join(save_directory, file_name)
   
  # 下载文件
  URI.open(direct_download_url) do |source|
    File.open(file_path, 'wb') do |file|
      file.write(source.read)
    end
  end
  puts "Saved #{file_name} to #{save_directory}"

  # 从Google Drive删除文件(此行报错)
  drive_service.delete_file(file_id)
end

报错信息

/Users/me/.rvm/gems/ruby-2.7.2/gems/google-apis-core-0.14.0/lib/google/apis/core/http_command.rb:244:in `check_status': insufficientFilePermissions: The user does not have sufficient permissions for this file. (Google::Apis::ClientError)

问题背景

  • Ruby脚本使用服务账号(servicename@servicename-412394.iam.gserviceaccount.com)的凭据,而Drive上的JSON文件归我的普通个人账号(myregularemail@gmail.com)所有
  • 已将存放文件的Drive文件夹共享给服务账号,服务账号拥有编辑权限,但仍无法删除文件
  • 不想把文件设为公开可编辑,但目前为了下载只能这么做
  • 不清楚如何让生成的文件直接归服务账号所有,也不知道如何用普通个人账号凭据运行Ruby脚本

解决方案

方案1:让服务账号直接拥有文件所有权(推荐)

修改Google Apps Script,将生成的JSON文件所有权直接转移给服务账号,这样Ruby脚本就能正常删除:

  1. 修改Apps Script代码
    在创建文件后添加转移所有权的代码,同时可以删除公开共享的逻辑:

    var file = folder.createFile(blob);
    // 添加此行:将服务账号设为文件所有者
    file.setOwner('servicename@servicename-412394.iam.gserviceaccount.com');
    // 删除公开共享的代码:file.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.EDIT);
    

    注意:你的个人账号必须拥有转移所有权的权限,且服务账号已被添加到Drive文件夹的共享列表中。

  2. 验证效果
    修改后生成的文件会直接归服务账号所有,Ruby脚本用服务账号凭据调用delete_file方法即可正常删除。

方案2:使用个人账号OAuth2授权运行Ruby脚本

如果不想转移文件所有权,可以改用个人账号的OAuth2授权来运行脚本:

  1. 创建OAuth2客户端凭据
    在Google Cloud控制台中创建桌面应用类型的OAuth客户端ID,下载JSON凭据文件(命名为oauth_client.json)。

  2. 修改Ruby脚本授权逻辑
    替换原服务账号授权代码为以下OAuth2授权代码:

    require 'google/apis/drive_v3'
    require 'googleauth'
    require 'googleauth/stores/file_token_store'
    require 'fileutils'
    
    OOB_URI = 'urn:ietf:wg:oauth:2.0:oob'.freeze
    APPLICATION_NAME = 'Drive File Manager'.freeze
    CREDENTIALS_PATH = 'oauth_client.json'.freeze
    TOKEN_PATH = 'token.yaml'.freeze # 存储授权令牌的文件
    SCOPE = Google::Apis::DriveV3::AUTH_DRIVE
    
    def authorize
      client_id = Google::Auth::ClientId.from_file(CREDENTIALS_PATH)
      token_store = Google::Auth::Stores::FileTokenStore.new(file: TOKEN_PATH)
      authorizer = Google::Auth::UserAuthorizer.new(client_id, SCOPE, token_store)
      user_id = 'default'
      credentials = authorizer.get_credentials(user_id)
      if credentials.nil?
        url = authorizer.get_authorization_url(base_url: OOB_URI)
        puts "打开以下URL并输入授权后的验证码:"
        puts url
        code = gets.chomp
        credentials = authorizer.get_and_store_credentials_from_code(
          user_id: user_id, code: code, base_url: OOB_URI
        )
      end
      credentials
    end
    
    # 初始化Drive服务
    drive_service = Google::Apis::DriveV3::DriveService.new
    drive_service.client_options.application_name = APPLICATION_NAME
    drive_service.authorization = authorize
    
    # 后续下载、删除代码保持不变
    

    第一次运行脚本时,会提示你打开授权URL,用个人账号登录授权,授权令牌会自动保存到token.yaml,后续运行无需重复授权。

方案3:在Apps Script中新增删除接口

如果上述方案都不适用,可以在Apps Script中添加删除接口,Ruby脚本下载后调用该接口删除文件:

  1. 修改Apps Script添加删除接口

    function doPost(e) {
      var fileId = e.parameter.fileId;
      try {
        var file = DriveApp.getFileById(fileId);
        file.setTrashed(true); // 移到回收站,用file.remove()可彻底删除
        return ContentService.createTextOutput(JSON.stringify({success: true})).setMimeType(ContentService.MimeType.JSON);
      } catch (error) {
        return ContentService.createTextOutput(JSON.stringify({success: false, error: error.message})).setMimeType(ContentService.MimeType.JSON);
      }
    }
    

    重新部署Web App,设置访问权限为**"任何人,甚至匿名"**(或限制为你的个人账号)。

  2. 修改Ruby脚本调用删除接口
    替换原删除代码为以下HTTP请求:

    # 先安装httparty库:gem install httparty
    require 'httparty'
    
    # 替换 drive_service.delete_file(file_id) 为:
    delete_url = 'https://script.google.com/macros/s/你的Web App ID/exec'
    response = HTTParty.post(delete_url, body: {fileId: file_id})
    puts response.parsed_response['success'] ? "Deleted #{file_name} from Drive" : "Delete failed: #{response.parsed_response['error']}"
    

内容的提问来源于stack exchange,提问作者soleil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 06:28:11