使用访问令牌调用 Google Apps 脚本网络应用

Calling a Google Apps Script web app with access token

我需要代表登录到我系统的用户执行 GAS 服务。所以我有 her/his 访问令牌。我想以某种方式将令牌传输到网络应用程序,而不必再次授权用户将其用于某些活动。这能实现吗?谢谢。

编辑: 我想我没有正确解释我想要完成的事情。这是我尝试实现的工作流程:

  1. 我们授权使用 OAuth2 和 Google 访问我们网站的用户;
  2. 我们获得 her/his 访问令牌 Google returns;
  3. 有一个 Google Apps Script 网络应用程序作为用户执行 运行 网络应用程序;
  4. 我们想通过提供访问令牌 (2) 来调用此应用程序 (3),这样 Google 就不会再次请求授权;
  5. 实际上,我们想要调用此应用程序 (3) 不是通过将用户重定向到它,而是通过将其作为 Web 服务来调用。

谢谢

很难回答是否定的,您不能将 Apps 脚本的内置服务与服务令牌一起使用。但是,如果您已经拥有服务帐户生成的用户令牌,则访问用户数据与任何其他语言非常相似。所有调用都将针对您的令牌范围内的服务的 REST 接口。

以这个小脚本为例。它将构建所有用户文件夹的列表,并将它们 return 作为 JSON:

 function doGet(e){
  var token = e.parameter.token;
  var folderArray = [];
  var pageToken = "";
  var query = encodeURIComponent("mimeType = 'application/vnd.google-apps.folder'");
  var params = {method:"GET",
                contentType:'application/json',
                headers:{Authorization:"Bearer "+token},
                muteHttpExceptions:true
               };

  var url = "https://www.googleapis.com/drive/v2/files?q="+query;

  do{
    var results = UrlFetchApp.fetch(url,params); 
    if(results.getResponseCode() != 200){
      Logger.log(results);
      break;
    }

    var folders = JSON.parse(results.getContentText());
    url = "https://www.googleapis.com/drive/v2/files?q="+query;  

    for(var i in folders.items){
      folderArray.push({"name":folders.items[i].title, "id":folders.items[i].id})
    }

    pageToken = folders.nextPageToken;
    url += "&pageToken="+encodeURIComponent(pageToken);
  }while(pageToken != undefined)

  var folderObj = {};
  folderObj["folders"] = folderArray;      
  return ContentService.createTextOutput(JSON.stringify(folderObj)).setMimeType(ContentService.MimeType.JSON);
}

您确实错过了让 Apps 脚本如此强大的许多便利,主要是内置服务,但所有功能都可以通过 Google REST API 获得。

我找到方法了!只需在请求中包含以下 header:

Authorization: Bearer <user's_access_token>

Martin 的回答最终对我有用,但是当我制作原型时遇到了一个主要障碍。

我需要手动添加以下范围,因为 google 应用程序脚本的 "automatic scope detection system" 没有要求它:"https://www.googleapis.com/auth/drive.readonly"。这导致 UrlFetchApp.fetch 总是向 401 提供我不理解的附加信息。记录此附加信息将显示 html,包括以下字符串

Sorry, unable to open the file at this time.</p><p> Please check the address and try again.

我还是不太明白为什么 "https://www.googleapis.com/auth/drive.readonly" 是必要的。可能与我们可以使用/devurl有关,但是谁可以使用/devurl是使用脚本文件的驱动权限来管理的。

就是说,下面的设置适用于我(它也适用于 doGet 等,但我选择了 doPost)。我选择在清单文件中明确列出最低限度需要的范围,但您也可以确保调用脚本将请求以不同方式访问驱动器的权限。我们有两个 google 应用程序脚本项目,Caller 和 WebApp。

在Caller的清单文件中,即appsscript.json

{
  ...
  "oauthScopes": 
  [
    "https://www.googleapis.com/auth/drive.readonly",
    "https://www.googleapis.com/auth/script.external_request"]
}

在 Code.gs 的来电者

function controlCallSimpleService(){

  var webAppUrl ='https://script.google.com/a/DOMAIN/macros/s/id123123123/exec';

//  var webAppUrl = 
//  'https://script.google.com/a/DOMAIN/macros/s/id1212121212/dev'

  var token = ScriptApp.getOAuthToken();

  var options = {
    'method' : 'post'
    , 'headers': {'Authorization': 'Bearer '+  token}
    , muteHttpExceptions: true
  };

  var response = UrlFetchApp.fetch(webAppUrl, options);
  Logger.log(response.getContentText());
}

在 WebApp 的 Code.gs 中(正在调用的网络应用程序)

function doPost(event){
  return ContentService.createTextOutput("Hello World");
}