Serving JSON from Google Apps Script as “user acce

2019-05-29 00:02发布

问题:

Trying to serve a JSON request made by a Google Apps Script as the user who is making the request. After thinking for a while, I realized that this cannot work, because the serving script needs to be authorized to run as the user who calls him, so the calling script would have to add some authorization info, which it doesn't, and I have no idea how to add that information (that is actually my question: which information to add to the http-request, and from where to get it).

But, nevertheless, when I call that server from within the browser, it works because the browser (in which I am logged into my Google account) sends the right info in the http-request to prove that it is authorized.

This question is somehow related to the question How to use Google Apps Script ContentService as a REST server, but the answer given there is exactly what I don't want: The invoked JSON-Server should not run under my account, but under the account of the invoking user and use that users resources (scriptdb, drive, ...). So the question is: How to provide that information from one script run from a Google-account to another script, so that this other script can run within that account? I know that using gas-libraries solves that issue, but I would like to have it as JSON-client/server (Mainly to decouple dependencies). To add some code (to keep the Stack Overflow-spirit running), my client:

var scriptUrl="https://script.google.com/macros/s/paperlapapp1231231/exec";
function callIt (nm, args) {
  var a=[nm];
  for (x in args) {
    a.push(args[x]);
  }
  return Utilities.jsonParse(UrlFetchApp.fetch(scriptUrl+"?args="
       +encodeURIComponent(Utilities.jsonStringify(a))).getContentText());
}
function testFunction (p1, p2, p3) { // this is the proxy
  return callIt ("testFunction", arguments);
}
// Testroutine
function callTest() {
  var r=testFunction (9, "XXXlala", {"dudu":1, "dada":"xxx"});
  Logger.log ("r="+Utilities.jsonStringify(r));
}

My server:

function doGet(request) {
  var ret=null;
  try {
    Logger.log ("I got called with "+JSON.stringify(request));
    var args=JSON.parse(decodeURIComponent (request.parameters.args));
    ret=ContentService.createTextOutput(
            JSON.stringify(this[args.shift()].apply (this, args)))
         .setMimeType(ContentService.MimeType.JSON);
  }
  catch (e) {
    ret=ContentService.createTextOutput(JSON.stringify(e))
          .setMimeType(ContentService.MimeType.JSON);
  }
  return ret;
}
function testFunction (p1, p2, p3) { // this is the implementation
  var s="testing called p1="+p1+", p2="+p2+", p3="+p3;
  Logger.log (s);
  return {testingResult:s};
}

EDIT:

Worked out a solution, but requires a Chrome extension and an intermediate proxy server. See code at https://bitbucket.org/pbhd/gas-rest-server-as-calling-user

回答1:

Edit: This was not possible before, as my answer below reflects. However, Google does allow this now, see Execution API https://developers.google.com/apps-script/execution/rest/v1/scripts/run


Its not possible to do that from Google Apps Script. If I understand it correctly you are calling another Google Apps Script with urlFetch.

Since Google Apps Script doesn't have an oAuth scope you can't make an authenticated call. You can only call a webapp service published as anonymous thus will run always under owner permissions.

You can't do it with libraries either unless the initial script is also called with user permissions and not owner.