带有 Google 云打印的 OAuth2

OAuth2 with Google Cloud Print

我写了一个 Google Apps 脚本连接到 Google Cloud Print 来自动化一些打印。该脚本会按时间间隔自动 运行,搜索相关文件,如果找到,它会将它们发送到我的打印机。我的代码使用 OAuthConfig 并且运行良好,但现在 class 已被弃用,经过一个周末的反复试验和搜索互联网后,我 不能'它无法与 OAuth2 一起使用。

这是工作正常的 OAuthConfig 代码

function printDoc(docId, docTitle, myPrinterId) {

  var scope = 'https://www.googleapis.com/auth/cloudprint';
  var url = 'https://www.google.com/cloudprint/submit'; 
  var payloadOfSubmit = {
    "printerid" : myPrinterId, 
    "title" : docTitle,
    "content"  : docId, 
    "contentType" : "google.kix"  
  };

  var fetchArgs = googleOAuth_('google', scope, payloadOfSubmit); 
  fetchArgs.method = 'POST';
  var responseOfSubmit = UrlFetchApp.fetch(url, fetchArgs);
  var jsonOfSubmit = JSON.parse(responseOfSubmit.getContentText()); 

  return jsonOfSubmit;
}

function googleOAuth_(name, scope, payloadData) {
  var oAuthConfig = UrlFetchApp.addOAuthService(name);
  oAuthConfig.setAuthorizationUrl("https://www.google.com/accounts/OAuthAuthorizeToken");
  oAuthConfig.setRequestTokenUrl("https://www.google.com/accounts/OAuthGetRequestToken?scope="+scope);
  oAuthConfig.setAccessTokenUrl("https://www.google.com/accounts/OAuthGetAccessToken");
  oAuthConfig.setConsumerKey("anonymous");
  oAuthConfig.setConsumerSecret("anonymous");
  return {
    oAuthServiceName:name, 
    oAuthUseToken:"always", 
    muteHttpExceptions:true, 
    payload:payloadData
  }; 
}  

我已成功连接 github library for OAuth2。但是,那里提供的说明与许多其他网站上的说明不同的是,它们假设代码将部署为 Web 服务,提示用户手动单击以授权请求。在我的例子中,代码将保存在 Google Apps 脚本文件中,并且云打印机在同一个 Google 帐户中,所以我从来不需要这种手动干预或来回使用我的原始 OAuthconfig。

我调整说明的第一次尝试是:

function printDoc2(docId, docTitle, myPrinterId) {

  var url = 'https://www.google.com/cloudprint/submit';
  var scope = 'https://www.googleapis.com/auth/cloudprint'; 
  var payloadOfSubmit = {
    "printerid" : myPrinterId, 
    "title" : docTitle,
    "content"  : docId, 
    "contentType" : "google.kix",
  };

  var accessToken = googleOAuth_('google', scope).getAccessToken();

  var params = {
    method:"POST",
    headers: {"Authorization": "Bearer " + accessToken},
    muteHttpExceptions:true,
    payload:payloadOfSubmit
  };

  var responseOfSubmit = UrlFetchApp.fetch(url, params);
  //Logger.log(responseOfSubmit);
  var jsonOfSubmit = JSON.parse(responseOfSubmit.getContentText()); 

  return jsonOfSubmit;
}

function googleOAuth2_(name, scope) {

  return OAuth2.createService(name)
    .setAuthorizationBaseUrl('https://accounts.google.com/o/oauth2/auth')
    .setTokenUrl('https://accounts.google.com/o/oauth2/token')
    .setClientId("anonymous")
    .setClientSecret("anonymous")
    .setProjectKey(ScriptApp.getProjectKey())
    .setPropertyStore(PropertiesService.getUserProperties())
    .setScope(scope)
    .setCallbackFunction('authCallback');
}

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

但这给了我一个错误 "Access not granted or expired" 当它试图 运行 行:

var accessToken = googleOAuth_('google', scope).getAccessToken();

所以我找到了一个应用程序 ScriptApp 方法 getOAuthToken,它似乎可以为我提供所需的令牌。我将上面的行替换为:

var accessToken = ScriptApp.getOAuthToken();

代码执行了,但服务器的响应是 "Error 403 User credentials required"。

这是我根据@Mogsdad 的建议进行的第三次尝试:

function sendPrintJob(docId,myPrinterId,docTitle) {

  var payloadOfSubmit = {
            "printerid" : myPrinterId, 
            "title" : docTitle,
            "content"  : docId, 
            "contentType" : "google.kix" ,
  };

  var request = {
    "method": "POST",
    "headers":{"Authorization": "Bearer "+ScriptApp.getOAuthToken()},    
    "muteHttpExceptions": true
  };

  var responseOfSubmit = UrlFetchApp.fetch("https://www.google.com/cloudprint/submit", request);
  Logger.log(responseOfSubmit);
}

我尝试了多种变体,包括创建开发人员控制台项目和使用那里提供的客户端 ID,但我一直被这两个问题所困(未授予访问权限,或需要凭据)。如果有人能提供任何帮助,我将不胜感激。

以下是允许我将 Google Apps 脚本连接到 Google Cloud Print 的步骤,这样我就可以提交 GCP 作业(这些步骤都是从 Google 中开始的应用程序脚本):

  1. 添加 OAuth2 库 (https://github.com/googlesamples/apps-script-oauth2) 给你的 Google Apps 脚本,方法是转到:资源 > 库 > 查找库 MswhXl8fVhTFUH_Q3UOJbXvxhMjh3Sh48 > Select
  2. 在 Developer Console Resources > Developer Console Project > 单击项目 link > APIs & Auth > 创建新的 Web 应用程序 凭据 > 添加凭据 > OAuth2.0 客户端 ID > Web Application > Set Authorized redirect URIs to the format
    https://script.google.com/macros/d/{PROJECT KEY}/usercallback 项目密钥位于文件 > 项目属性下并复制 您的客户端 ID 和客户端密码
  3. 将 ID 和 Secret 添加到下面的 "getCloudPrintService()" 代码中(替换 client_idclient_secret
  4. 转到 运行 > 显示URL 并授权脚本。
  5. 打开记录器(Cmd + Enter),复制URL并粘贴到新的浏览器选项卡中以完成授权。
  6. 转到 https://www.google.com/cloudprint/#printers,select 您的打印机,单击详细信息,展开高级详细信息,然后复制您的 Printer ID(格式为 555aa555-5a55-5555-5555-55555a55a555
  7. 将打印机 ID 添加到下面的 "printGoogleDocument()" 代码中(替换 myPrinterId

此资源有助于确定步骤:http://ctrlq.org/code/20061-google-cloud-print-with-apps-script,您可能还会发现这些 link 有帮助:

function showURL() {
  var cpService = getCloudPrintService();
  if (!cpService.hasAccess()) {
    Logger.log(cpService.getAuthorizationUrl());
  } else {
    Logger.log("You already have access to this service.");
  }
}
 
function getCloudPrintService() {
  return OAuth2.createService('print')
    .setAuthorizationBaseUrl('https://accounts.google.com/o/oauth2/auth')
    .setTokenUrl('https://accounts.google.com/o/oauth2/token')
    .setClientId(client_id)
    .setClientSecret(client_secret)
    .setCallbackFunction('authCallback')
    .setPropertyStore(PropertiesService.getUserProperties())
    .setScope('https://www.googleapis.com/auth/cloudprint')
    .setParam('login_hint', Session.getActiveUser().getEmail())
    .setParam('access_type', 'offline')
    .setParam('approval_prompt', 'force');
}
 
function authCallback(request) {
  var isAuthorized = getCloudPrintService().handleCallback(request);
  if (isAuthorized) {
    return HtmlService.createHtmlOutput('You can now use Google Cloud Print from Apps Script.');
  } else {
    return HtmlService.createHtmlOutput('Cloud Print Error: Access Denied');
  }
}

function getPrinterList() {
  var response = UrlFetchApp.fetch('https://www.google.com/cloudprint/search', {
    headers: {
      Authorization: 'Bearer ' + getCloudPrintService().getAccessToken()
    },
    muteHttpExceptions: true
  }).getContentText();
 
  var printers = JSON.parse(response).printers;
 
  for (var p in printers) {
    Logger.log("%s %s %s", printers[p].id, printers[p].name, printers[p].description);
  }
}

function printGoogleDocument(docId, docTitle) {  
  // For notes on ticket options see https://developers.google.com/cloud-print/docs/cdd?hl=en
  var ticket = {
    version: "1.0",
    print: {
      color: {
        type: "STANDARD_COLOR"
      },
      duplex: {
        type: "NO_DUPLEX"
      },
    }
  };
   
  var payload = {
    "printerid" : myPrinterId,
    "content"   : docId,
    "title"  : docTitle,
    "contentType" : "google.kix", // allows you to print google docs
    "ticket"    : JSON.stringify(ticket),
  };
 
  var response = UrlFetchApp.fetch('https://www.google.com/cloudprint/submit', {
    method: "POST",
    payload: payload,
    headers: {
      Authorization: 'Bearer ' + getCloudPrintService().getAccessToken()
    },
    "muteHttpExceptions": true
  });
 
  // If successful, should show a job here: https://www.google.com/cloudprint/#jobs

  response = JSON.parse(response);
  if (response.success) {
    Logger.log("%s", response.message);
  } else {
    Logger.log("Error Code: %s %s", response.errorCode, response.message);
  }
  return response;
}

范围“https://www.googleapis.com/auth/cloudprint" has to be included explicitlymanifest file

appscript.json(查看 > 显示清单文件)

{
  "timeZone": "Europe/Paris",
  "dependencies": {
  },
  "oauthScopes": [
    "https://www.googleapis.com/auth/documents",
    "https://www.googleapis.com/auth/drive",
    "https://www.googleapis.com/auth/script.container.ui",
    "https://www.googleapis.com/auth/script.external_request",
    "https://www.googleapis.com/auth/spreadsheets",
    "https://www.googleapis.com/auth/cloudprint"
  ],
  "exceptionLogging": "STACKDRIVER"
}

Code.gs

function listPrinters() {
  var options = {
    headers: {
      authorization: 'OAuth ' + ScriptApp.getOAuthToken()
    }
  }
  var response = UrlFetchApp.fetch('https://www.google.com/cloudprint/search', options);
  Logger.log(response);
}