5

我正在尝试使用 Google 脚本创建一个附加组件以在 Google 电子表格中使用。 

在附加组件中,我连接到需要我进行 OAuth 的第三方 API(此处为 Pocket API)。在使用 OAuth 时,我需要在调用 Pocket 的授权 API 时提供一个重定向 URI。 

根据此链接上的信息:  https://github.com/gsuitedevs/apps-script-oauth2,在这种情况下,重定向 URI 的格式为 https://script.google.com/macros/d/ {SCRIPT ID }/用户回调。我使用了这种格式,但出现“无法打开文件”的错误。我使用“OAuth2.getRedirectUri()”来获取重定向 URI。

澄清我得到的评论:我没有直接打开重定向 URI。我在对 Pocket API 的调用中指定了它。这是完整的代码:

/**
 * @OnlyCurrentDoc  Limits the script to only accessing the current spreadsheet.
 */

var API_KEY = '87572-369f6490c104433f539c40d6';
var FIRST_TOKEN = '';

/**
 * Adds a custom menu with items to show the sidebar and dialog.
 *
 * @param {Object} e The event parameter for a simple onOpen trigger.
 */
function onOpen(e) {
  SpreadsheetApp.getUi()
      .createAddonMenu()
      .addItem('Show articles', 'getPocketArticles')
      .addToUi();
}

/**
 * Runs when the add-on is installed; calls onOpen() to ensure menu creation and
 * any other initializion work is done immediately.
 *
 * @param {Object} e The event parameter for a simple onInstall trigger.
 */
function onInstall(e) {
  onOpen(e);
}

/*

*/

function getPocketArticles() {
  // URL and params for the Pocket API
  var root = 'https://getpocket.com/v3/';
  var pocketService = getPocketService();
  getPocketToken(root);
}

function getPocketToken(root) {

  var url = root + 'oauth/request';

  var payloadData = {
      'consumer_key': API_KEY,
      'redirect_uri': OAuth2.getRedirectUri(),
      'state': ScriptApp.newStateToken()
                      .withMethod(usercallback)
                      .withTimeout(3600)
                      .createToken()
    };

  // parameters for url fetch
  var params = {
    'method': 'POST',
    'contentType': 'application/json; charset=UTF8',
    'headers': {
       'X-Accept' : 'application/json'
    },
    'payload': JSON.stringify(payloadData)
  };

  Logger.log(params);

  // call the Pocket API
  var response = UrlFetchApp.fetch(url, params);
  var data = response.getContentText();
  var json = JSON.parse(data);
  FIRST_TOKEN = json['code'];
  Logger.log("First token: "+FIRST_TOKEN);

  showSidebar(root);
}


/*
 * Register the Pocket Service
*/

function getPocketService() {
  // Create a new service with the given name. The name will be used when
  // persisting the authorized token, so ensure it is unique within the
  // scope of the property store.
  return OAuth2.createService('pocket')

      // Set the endpoint URLs.
      //.setAuthorizationBaseUrl('https://getpocket.com/auth/authorize')
      .setAuthorizationBaseUrl('https://getpocket.com/auth/authorize?request_token='+FIRST_TOKEN)

      /*.setTokenUrl('')*/

      // Set the client ID and secret, from the Google Developers Console.
      .setClientId(API_KEY)
      .setClientSecret(FIRST_TOKEN)

      // Set the name of the callback function in the script referenced
      // above that should be invoked to complete the OAuth flow.
      .setCallbackFunction('usercallback')

      // Set the property store where authorized tokens should be persisted.
      .setPropertyStore(PropertiesService.getUserProperties())

      // Set the scopes to request (space-separated for Google services).
      /*.setScope('')*/

      // Below are Google-specific OAuth2 parameters.

      // Sets the login hint, which will prevent the account chooser screen
      // from being shown to users logged in with multiple accounts.
      //.setParam('login_hint', Session.getActiveUser().getEmail())

      // Requests offline access.
      //.setParam('access_type', 'offline')

      // Forces the approval prompt every time. This is useful for testing,
      // but not desirable in a production application.
      //.setParam('approval_prompt', 'force');

     .setTokenHeaders({
      /*'Authorization': 'Basic ' +
          Utilities.base64Encode(CLIENT_ID + ':' + CLIENT_SECRET),*/
       'request_token': FIRST_TOKEN,
       'X-Accept' : 'application/json'
      })
  /*
    // Avoid "invalid_client error".
    // This service does not support form field authentication.
    .setTokenPayloadHandler(function(tokenPayload) {
      delete tokenPayload.client_id;
      return tokenPayload;
    })*/

     // Setting Payload 
     .setTokenPayloadHandler(function(tokenPayload) {
      tokenPayload.state = ScriptApp.newStateToken()
                      .withMethod(usercallback)
                      .withTimeout(3600)
                      .createToken();
      return tokenPayload;
    })

  ;


}

/**
 * Opens a sidebar. The sidebar structure is described in the Sidebar.html
 * project file.
 */
function showSidebar(root) {  
  var pocketService = getPocketService();
  var authorizationUrl = pocketService.getAuthorizationUrl();
  Logger.log("Authorization URL: " + authorizationUrl);

  if (!pocketService.hasAccess()) {
    var template = HtmlService.createTemplate(
        '<a href="<?= authorizationUrl ?>" target="_blank">Authorize</a>. ' +
        'Reopen the sidebar when the authorization is complete.');
    template.authorizationUrl = authorizationUrl;
    var page = template.evaluate();
    SpreadsheetApp.getUi().showSidebar(page);
  } else {
  // ...
  getPermanentToken(root);
  }


}


/**
 * 
 */

function getPermanentToken(root) {

  var url = root + 'oauth/authorize';

  var payloadData = {
      'consumer_key': API_KEY,
      'code': FIRST_TOKEN
    };

  // parameters for url fetch
  var params = {
    'method': 'POST',
    'muteHttpExceptions': false,
    'contentType': 'application/json; charset=UTF8',
    'headers': {
       'X-Accept' : 'application/json'
    },
    'payload': JSON.stringify(payloadData)
  };

  /*'contentType': 'application/json',*/

  // call the Pocket API
  Logger.log("URL: "+url+"\nparams: "+JSON.stringify(params));
  var response = UrlFetchApp.fetch(url, params);
  Logger.log("Response: "+response.getAllHeaders());

}

/**
 * Handle Callback 
 * 
 */

function usercallback(request) {
  var pocketService = getPocketService();
  var isAuthorized = pocketService.handleCallback(request);
  if (isAuthorized) {
    return HtmlService.createHtmlOutput('Success! You can close this tab.');
  } else {
    return HtmlService.createHtmlOutput('Denied. You can close this tab');
  }
}



我是根据上面共享的 github 链接上给出的指南以及https://github.com/gsuitedevs/apps-script-oauth2/tree/master/samples上提到的示例完成此操作的。这些示例并不完全适用于我,因为 Pocket 的 API 的行为似乎有点不同(或者我理解)

我也为授权 URL 放置了记录器语句。它显示在我在下面共享的日志中。

执行记录日志:

[19-09-16 07:36:45:329 IST] Starting execution
[19-09-16 07:36:45:342 IST] PropertiesService.getUserProperties() [0 seconds]
[19-09-16 07:36:45:342 IST] ScriptApp.getScriptId() [0 seconds]
[19-09-16 07:36:45:344 IST] Logger.log([{headers={X-Accept=application/json}, method=POST, payload={"consumer_key":"87572-369f6490c104433f539c40d6","redirect_uri":"https://script.google.com/macros/d/1QWlUgkmucy_wXK3v1BUjbxh9Ei1bBan7AFL2Jce...) [0 seconds]
[19-09-16 07:36:45:513 IST] UrlFetchApp.fetch([https://getpocket.com/v3/oauth/request, {headers={X-Accept=application/json}, method=POST, payload={"consumer_key":"87572-369f6490c104433f539c40d6","redirect_uri":"https://script.google.com/macros/d/...) [0.168 seconds]
[19-09-16 07:36:45:513 IST] HTTPResponse.getContentText() [0 seconds]
[19-09-16 07:36:45:514 IST] Logger.log([First token: 5c9102f2-3feb-caa6-86f0-c4530e, []]) [0 seconds]
[19-09-16 07:36:45:515 IST] PropertiesService.getUserProperties() [0 seconds]
[19-09-16 07:36:45:516 IST] ScriptApp.newStateToken() [0 seconds]
[19-09-16 07:36:45:516 IST] StateTokenBuilder.withMethod([usercallback]) [0 seconds]
[19-09-16 07:36:45:517 IST] StateTokenBuilder.withArgument([serviceName, pocket]) [0 seconds]
[19-09-16 07:36:45:517 IST] StateTokenBuilder.withTimeout([3600]) [0 seconds]
[19-09-16 07:36:45:517 IST] ScriptApp.getScriptId() [0 seconds]
[19-09-16 07:36:45:517 IST] StateTokenBuilder.createToken() [0 seconds]
[19-09-16 07:36:45:518 IST] Logger.log([Authorization URL: https://getpocket.com/auth/authorize?request_token=5c9102f2-3feb-caa6-86f0-c4530e&client_id=87572-369f6490c104433f539c40d6&response_type=code&redirect_uri=https%3A%2F%2Fscript.goog...) [0 seconds]
[19-09-16 07:36:45:523 IST] Properties.getProperty([oauth2.pocket]) [0.005 seconds]
[19-09-16 07:36:45:525 IST] HtmlService.createTemplate([<a href="<?= authorizationUrl ?>" target="_blank">Authorize</a>. Reopen the sidebar when the authorization is complete.]) [0.001 seconds]
[19-09-16 07:36:45:525 IST] Function.apply([[]]) [0 seconds]
[19-09-16 07:36:45:526 IST] HtmlService.createHtmlOutput() [0 seconds]
[19-09-16 07:36:45:527 IST] HtmlOutput.append([<a href="]) [0 seconds]
[19-09-16 07:36:45:528 IST] HtmlOutput.appendUntrusted([https://getpocket.com/auth/authorize?request_token=5c9102f2-3feb-caa6-86f0-c4530e&client_id=87572-369f6490c104433f539c40d6&response_type=code&redirect_uri=https%3A%2F%2Fscript.google.com%2Fmacros%2Fd...) [0 seconds]
[19-09-16 07:36:45:528 IST] HtmlOutput.append([" target="_blank">Authorize</a>. Reopen the sidebar when the authorization is complete.]) [0 seconds]
[19-09-16 07:36:45:529 IST] HtmlOutput.append([]) [0 seconds]
[19-09-16 07:36:45:530 IST] SpreadsheetApp.getUi() [0 seconds]
[19-09-16 07:36:45:595 IST] Ui.showSidebar([HtmlOutput]) [0.064 seconds]
[19-09-16 07:36:45:658 IST] Execution succeeded [0.255 seconds total runtime]

我在代码中的记录器语句的输出:

[19-09-16 07:36:45:343 IST] {headers={X-Accept=application/json}, method=POST, payload={"consumer_key":"87572-369f6490c104433f539c40d6","redirect_uri":"https://script.google.com/macros/d/1QWlUgkmucy_wXK3v1BUjbxh9Ei1bBan7AFL2JceT2401-ztkEtFk9-xb/usercallback"}, contentType=application/json; charset=UTF8}
[19-09-16 07:36:45:514 IST] First token: 5c9102f2-3feb-caa6-86f0-c4530e
[19-09-16 07:36:45:518 IST] Authorization URL: https://getpocket.com/auth/authorize?request_token=5c9102f2-3feb-caa6-86f0-c4530e&client_id=87572-369f6490c104433f539c40d6&response_type=code&redirect_uri=https%3A%2F%2Fscript.google.com%2Fmacros%2Fd%2F1QWlUgkmucy_wXK3v1BUjbxh9Ei1bBan7AFL2JceT2401-ztkEtFk9-xb%2Fusercallback&state=ADEpC8z2oP8q4juC4cgceCqVZw34DEX3KTdN9Cm5fPX-Nh7vzYIDdw50GIHNMfQ--Y92uqA_K8RUaAaHf7OU9O72RPOQ3ryYBVTrlQ-ZLZRQRgJ5Re68KOTud8ckAnonjG24a5-W2ti7g3o5rQebaDnhIlTLjY2MJWrP68pf70FSak6nhby7B_quV6PCmIjbCfS0R54D6oV3tTCwrL9JpO62zxmIHLkceD0O-cZc8SUrJK1yMDBcofuZCqGIxjlBOVpnCvugSnhCczp3qCaEA-3cLj3jwzXDX4XluqX7c-0hWsrkgHQNFxiB7qFo7pzhd8NlBcVj4t6yoQyTfquYN84C1wGKxcjtfg

发生的情况是,当我调用此 URL 时,我被重定向到 Pocket 授权页面,该页面要求我授权此加载项有权访问我的 Pocket 数据。这很好,但是当我点击授权时,我得到“无法打开文件”的错误。这是它的屏幕截图:https ://photos.app.goo.gl/VVCcEfh6NYTWK6MW9

我想知道我哪里出错了。有人可以指导我吗?

我是 Google Scripts 和 OAuth 的新手,所以如果这是一个愚蠢的问题,请原谅。

4

0 回答 0