Como se autenticar programaticamente ao executar um aplicativo da Web do Apps Script de outro projeto do Apps Script

Nov 16 2020

Eu sou novo no Apps Script e estou tentando entender os fundamentos da execução / acionamento de um script em uma conta usando outra. Com apenas uma ressalva: gostaria de executar o script com o usuário acessando o script em vez de o usuário possuir o script - a fim de atribuir o tempo de execução ao usuário acessando.

No entanto, estou tendo os seguintes problemas.


Começando com uma planilha de teste com compartilhamento definido como Qualquer pessoa com link pode editar e o seguinte código na página do projeto de script:

function doPost(e){
  var sheet = SpreadsheetApp.openById('1tWV6ELJEGkWkSXvdf9kQemvH-tDVTx0od4JHht2ZBeU');
  var tab = sheet.getSheetByName('ref');
  tab.getRange(1,1).setValue(new Date());
  return ContentService.createTextOutput(0)
}

function doGet(e){
  return doPost(e)
}

e ter publicado o projeto como um aplicativo da Web com execução definida para acesso do usuário e acesso habilitado para qualquer pessoa. Inserir o seguinte link no navegador preenche manualmente a célula A1 com a hora atual e a página exibindo '0', conforme pretendido,

https://script.google.com/macros/s/AKfycbwNhYg1BRKi38pNf_z0peGuYt6gsqvauCvo-eiGgCYJJk4QDpjm/exec

SE eu entrar no link enquanto ainda estiver conectado com a conta que criou o SpreadSheet de teste.

Se eu entrar no link com um navegador diferente sem o login do GSuite, sou obrigado a fazer o login, o que também é o esperado. Afinal, uma conta do G Suite é necessária para executar o script por implantação do Web App.

No entanto, quando tentei acionar o script usando uma conta GSuite diferente e um projeto do Apps Script, ainda encontrei a página de login e também outros problemas. Fora de

function test1(){
  const scriptURL='https://script.google.com/macros/s/AKfycbwNhYg1BRKi38pNf_z0peGuYt6gsqvauCvo-eiGgCYJJk4QDpjm/exec';  
  var response = UrlFetchApp.fetch(scriptURL)
  Logger.log(response.getContentText())
}

function test2(){
  const scriptURL='https://script.google.com/macros/s/AKfycbxay75fTBt3doTyMFUPK0-GpK9hMZ4hVkYdiwYUBMhPfEN6hUJH/exec';  
  var response = UrlFetchApp.fetch(scriptURL, {
    method:'POST',
    payload:'nothing'
  });  
  Logger.log(response.getContentText())
}

function test3() {
  var sheet = SpreadsheetApp.openById('AKfycbwNhYg1BRKi38pNf_z0peGuYt6gsqvauCvo-eiGgCYJJk4QDpjm');
  Logger.log(sheet.getName());
}

function test4() {
  var token = ScriptApp.getOAuthToken();
  const scriptURL='https://script.google.com/macros/s/AKfycbxay75fTBt3doTyMFUPK0-GpK9hMZ4hVkYdiwYUBMhPfEN6hUJH/exec';  
  var response = UrlFetchApp.fetch(scriptURL, {
    headers: {Authorization:'Bearer '+ token},
    method:'GET',
    payload:'nothing'
  });  
  Logger.log(response.getContentText())
}

test1() produz um longo corpo de texto no Log começando com

Logging output too large. Truncating output. 
<!DOCTYPE html>
<html lang="en">
  <head>
  <meta charset="utf-8">
  <meta content="width=300, initial-scale=1" name="viewport">
  <meta name="google-site-verification" content="LrdTUW9psUAMbh4Ia074-BPEVmcpBxF6Gwf0MSgQXZs">
  <title>Sign in - Google Accounts</title>
  <style>

e test2()retorna um erro

Exception: Request failed for https://script.google.com returned code 401. Truncated server response: <!DOCTYPE html><html lang="en"><head><meta name="description" content="Web word processing, presentations and spreadsheets"><meta name="viewport" c... (use muteHttpExceptions option to examine full response)
    at test2(Code:23:30)

Nenhum dos testes acionou o script, doPost(e)pois a célula A1 não foi atualizada.

test1()parece encontrar a página de login. No entanto, ao mesmo tempo, test1()é executado por meio de uma conta do G Suite de login.

Também pode ser importante observar que test3()é possível acessar o arquivo Google SpreadSheet em questão. Eu também tentei ligar ScriptApp.getOAuthToken()porque não. test4()tem a mesma resposta que test1().

Não sei por onde começar a diagnosticar o erro encontrado em test2().


Como faço para contornar a página de login?

Em particular, há uma maneira de tornar o script acessível por qualquer outra conta do GSuite com permissão de acesso ao Google SpreadSheet em questão e executado pelo usuário que acessa em vez do usuário que possui o SpreadSheet?

O que estou fazendo de errado com a versão POST?

Qualquer ajuda é necessária!

Respostas

4 Tanaike Nov 17 2020 at 06:49

A partir de sua pergunta, entendi sua situação da seguinte maneira.

  • O script de Web Apps é colocado no script de contêiner da planilha de 1tWV6ELJEGkWkSXvdf9kQemvH-tDVTx0od4JHht2ZBeU.
  • A planilha é compartilhada a partir Anyone with the linkde editor.
  • Os aplicativos da Web são implantados como Execute the app as: User accessing the web appse Who has access to the app: Anyone.

Esta resposta supõe meu entendimento acima. Então, quando meu entendimento não estiver correto, por favor me diga.

Pontos de modificação:

  • Em UrlFetchApp, quando payload:'nothing'é usado, ele solicita como método POST mesmo quando method:'GET'é usado. Por favor, tome cuidado com isso.
  • Em seu script de Web Apps usa o escopo de https://www.googleapis.com/auth/spreadsheets. Nesse caso, em um primeiro momento, é necessário autorizar o escopo pelo próprio navegador (o navegador de cada usuário). Quando isso não é feito, mesmo quando o script e o token de acesso com os escopos do lado do cliente estão corretos, Authorization neededocorre um erro de . Por favor, tome cuidado com isso. Parece que esta é a especificação atual.
  • Se todo o script ( test1to test4) do lado do cliente for o script da sua pergunta, os escopos serão https://www.googleapis.com/auth/script.external_requeste https://www.googleapis.com/auth/spreadsheets. Acho que o escopo não é suficiente para solicitar os Web Apps. Neste caso, por exemplo, adicione // DriveApp.getFiles()ao editor de script. Com isso, o escopo de https://www.googleapis.com/auth/drive.readonlyé adicionado automaticamente pelo editor de script e esse escopo pode ser usado para solicitar aplicativos da Web. Além disso, você pode usar o escopo de https://www.googleapis.com/auth/drive.
    • No caso de escopos de https://www.googleapis.com/auth/script.external_requeste https://www.googleapis.com/auth/spreadsheets, Unauthorizedocorre um erro de .

Quando os pontos acima são refletidos em sua situação, torna-se o seguinte.

Uso:

1. Prepare o lado dos aplicativos da Web. (lado do servidor)

Nesse caso, acho que suas configurações podem ser usadas. Reimplante os aplicativos da Web como uma nova versão para o caso. E confirme o URL dos aplicativos da Web novamente.

2. Prepare o lado do cliente.

  1. Acesse https://script.google.com/macros/s/AKfycbxay75fTBt3doTyMFUPK0-GpK9hMZ4hVkYdiwYUBMhPfEN6hUJH/execusando o próprio navegador (lado do usuário.) E autorize os escopos de Web Apps.

  2. Eu gostaria de propor a modificação test4()de seu script da seguinte maneira.

     function test4() {
       var token = ScriptApp.getOAuthToken();
       const scriptURL='https://script.google.com/macros/s/AKfycbxay75fTBt3doTyMFUPK0-GpK9hMZ4hVkYdiwYUBMhPfEN6hUJH/exec';  
       var response = UrlFetchApp.fetch(scriptURL, {
         headers: {Authorization:'Bearer '+ token},
         method: 'GET',
     //    payload:'nothing',
         muteHttpExceptions: true
       });  
       Logger.log(response.getContentText())
    
       // DriveApp.getFiles()  // This is used for adding a scope of https://www.googleapis.com/auth/drive.readonly. This is used for requesting to Web Apps.
     }
    
  3. Por favor, corra test4(). Por isso, 0é retornado de Web Apps e você pode vê-lo no log.

Referências:

  • Aproveitando as vantagens do Web Apps com o Google Apps Script
  • buscar (url, params)