通过库返回的OAuth2支持状态令牌无效或已过期。请再试一次

时间:2015-03-25 22:13:56

标签: google-apps-script oauth-2.0 google-oauth2

我的电子表格需要由我的组织中的各个用户转换为PDF。为此,我尝试使用OAuth2(https://github.com/googlesamples/apps-script-oauth2)。

当我在主电子表格嵌入式脚本中使用它时,它可以工作。但是,我试图将OAuth2代码移动到一个单独的库,因为会有许多电子表格需要相同的功能。当我使用这个库时,我收到消息“状态令牌无效或已过期。请再试一次。”

图书馆代码:

var PROPERTY_KEY = "ExportPdfOauth2";

function initialStore() {
  setAuthenticationPackage_( {
    clientId : '10511......b43bu.apps.googleusercontent.com',
    clientSecret : 'WYUsq...-h_',
    projectKey : 'MxJ.......xOvW',
    scopes : ['https://spreadsheets.google.com/feeds/']
  });
}

function setAuthenticationPackage_(package) {
  PropertiesService.getScriptProperties().setProperty(PROPERTY_KEY, JSON.stringify(package));
}

function getAuthenticationPackage_() {
  var p = PropertiesService.getScriptProperties().getProperty(PROPERTY_KEY);
  return p ? JSON.parse(p) : {};
}

function getExportPdfService() {
  // 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.

  var package = getAuthenticationPackage_();

  return OAuth2.createService('exportPdf')

      // Set the endpoint URLs, which are the same for all Google services.
      .setAuthorizationBaseUrl('https://accounts.google.com/o/oauth2/auth')
      .setTokenUrl('https://accounts.google.com/o/oauth2/token')

      // Set the client ID and secret, from the Google Developers Console.
      .setClientId(package.clientId)
      .setClientSecret(package.clientSecret)

      // Set the project key of the script using this library.
      .setProjectKey(package.projectKey)

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

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

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

      // 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');
}

function authCallback(request) {
  var user = Session.getActiveUser().getEmail();
  var exportPdfService = getExportPdfService();
  var isAuthorized = exportPdfService.handleCallback(request);
  if (isAuthorized) {
    return HtmlService.createHtmlOutput('Success');
  } else {
    return HtmlService.createHtmlOutput('Failure');
  }
}

function getExportPdfRequest() {
  var user = Session.getActiveUser().getEmail();
  var exportPdfService = getExportPdfService();
  if (!exportPdfService.hasAccess()) {
    var template = HtmlService.createTemplate('Authorisation required in order to enable conversion to pdf. You will need to perform the operation again once the authorisation is complete.')+
      '<br /><br />'+
      '<a href="<?= authorizationUrl ?>" target="_blank">'+
      'Authorise'+
      '</a>');
    template.authorizationUrl = exportPdfService.getAuthorizationUrl();
    var page = template.evaluate();
    SpreadsheetApp.getUi().showSidebar(page);
    return null;
  }

  var request = {
    headers: {
      Authorization: 'Bearer ' + exportPdfService.getAccessToken()
    }
  };

  return request;
}

嵌入式脚本调用库如下(请注意我在这里放了一个回调函数来回调库):

function test(){
  var id = 'ABCD.....'; // Spreadsheet to be converted to pdf
  var name = 'test.pdf';
  var domain = 'XXXXX';

  var pdfContent = spreadsheetToPDF(id,domain,name);
  if (pdfContent) DocsList.createFile(pdfContent);
}

// Convert spreadsheet to PDF file.
function spreadsheetToPDF(id,domain,name) {
  SpreadsheetApp.flush();

  var request = testPdfLib.getExportPdfRequest();
  if (!request) return null;

  //define the params URL to fetch
  var params = '?fitw=true&exportFormat=pdf&format=pdf&size=A4&portrait=true&sheetnames=false&printtitle=false&gridlines=false&pagenum=CENTER';
  var url = "https://docs.google.com/a/"+domain+"/spreadsheets/d/"+id+"/export"+params;

  //fetching file url
  var blob = UrlFetchApp.fetch(url, request);
  blob = blob.getBlob().setName(name);

  //return file
  return blob;
}

function authCallback(request) {
  testPdfLib.authCallback(request);
}

我还查看了How to correctly construct state tokens for callback urls in Managed Libraries?的另一篇文章,但由于我在主调用脚本中提供了回调函数,但仍无法弄清楚我做错了什么。在开发人员控制台上,我的REDIRECT URIS指向图书馆。我试图将它指向主脚本,但我得到相同的结果(虽然我不想这样做,因为脚本将被许多用户复制,并且不可能为每个实例创建一个新的客户端ID调用脚本)。

感谢任何帮助!

0 个答案:

没有答案