Google Service Accounts / API - I keep getting the Error: Access not granted or expired. (line 454, file "Service")

Google Service Accounts / API - I keep getting the Error: Access not granted or expired. (line 454, file "Service")

我已经搜索了几个小时来寻找这个问题的答案,所以请耐心等待!

我正在使用 Apps 脚本连接到 Google 驱动器 API。我已经在控制台中创建了一个服务帐户,并收集了相关的凭据。我有以下代码:

function test()
{


function getOAuthService(user) {
var JSON = {
    "private_key": "-----BEGIN PRIVATE KEY-----\nMY KEY HERE\n",
    "client_email": "clientemail@clientemail.iam.gserviceaccount.com",
    "client_id": "11111111111111",
    "user_email": "myemail@myemail.com"
};
    return OAuth2.createService("Service Account")
        .setTokenUrl('https://accounts.google.com/o/oauth2/token')
        .setPrivateKey(JSON.private_key)
        .setIssuer(JSON.client_email)
        .setSubject(JSON.user_email)
        .setPropertyStore(PropertiesService.getScriptProperties())
        .setParam('access_type', 'offline')
        .setScope('https://www.googleapis.com/auth/drive');
}

function getUserFiles() {
    var service = getOAuthService();
    service.reset();

        var url = 'https://www.googleapis.com/drive/v2/files?pageSize=1';
        var response = UrlFetchApp.fetch(url, {
            headers: {
                Authorization: 'Bearer ' + service.getAccessToken()
            }, muteHttpExceptions: true
        });
        Logger.log(response.getContentText());
    
}

function reset() {
    var service = getOAuthService();
    service.reset();
}

getUserFiles()
}

我还在脚本中添加了 OAuth2 库。

每次我 运行 我都会遇到以下错误:错误:访问未被授予或已过期。 (第 454 行,文件“服务”)

有人有什么想法吗?

谢谢!

下面的修改怎么样?

发件人:

return OAuth2.createService("Service Account")
    .setTokenUrl('https://accounts.google.com/o/oauth2/token')
    .setPrivateKey(JSON.private_key)
    .setIssuer(JSON.client_email)
    .setSubject(JSON.user_email)
    .setPropertyStore(PropertiesService.getScriptProperties())
    .setParam('access_type', 'offline')
    .setScope('https://www.googleapis.com/auth/drive');

收件人:

return OAuth2.createService("Service Account")
    .setTokenUrl('https://accounts.google.com/o/oauth2/token')
    .setPrivateKey(JSON.private_key)
    .setIssuer(JSON.client_email)
    // .setSubject(JSON.user_email)  // <--- Removed
    .setPropertyStore(PropertiesService.getScriptProperties())
    .setParam('access_type', 'offline')
    .setScope('https://www.googleapis.com/auth/drive');

注:

  • 作为附加信息,当服务帐户检索文件列表时,该驱动器与您的 Google 帐户的 Google 驱动器不同。请注意这一点。如果你想获取你的Google Drive的文件列表,比如当你的Google Drive中的一个文件夹与服务账号的邮箱共享时,可以通过以下方式获取该文件夹中的文件列表服务帐户。

  • 来自 Iamblichus 的评论。 and

    • 如果服务帐户已被授予域范围的权限并且 OP 想要使用 SA 来模拟域中的另一个用户(这是通过 .setSubject 完成的),那么原始代码就可以了但如果未设置域范围的委派则将不起作用)。但由于 OP 想要访问服务帐户的云端硬盘,而不是冒充另一个帐户,因此没有理由使用 .setSubject.

参考:

您可以使用高级驱动服务列出文件。您不需要 OAuth 库,甚至不需要 OAuth 令牌。您需要从“资源”菜单和“高级 Google 服务”菜单选项启用高级驱动服务。

function listFiles() {
  var file;
  
  var query = 'trashed = false';
  var files;
  var pageToken;
  do {
    files = Drive.Files.list({
      q: query,
      maxResults: 100,
      pageToken: pageToken
    });
    if (files.items && files.items.length > 0) {
      for (var i = 0; i < files.items.length; i++) {
        file = files.items[i];
        Logger.log('%s (ID: %s)', file.title, file.id);
      }
    } else {
      Logger.log('No files found.');
    }
    pageToken = files.nextPageToken;
  } while (pageToken);
}

Tanalike 的回答末尾的注释在这里起作用 - 我的问题是没有将我的服务帐户电子邮件添加到 Google 云端硬盘。我用我的服务电子邮件替换了 user_email(并将此电子邮件地址共享到云端硬盘中的一个文件夹)并且它运行良好。感谢您的帮助!