如何使用OAuth2库从Google App脚本发布推文?

问题描述

我已经成功地使用OAuth1将我的GAS进行了鸣叫。已知OAuth1 GAS库已过时,因此我正尝试迁移到OAuth2库。

我看到了一些变化,但是我没有正确的方法来授权我的请求。

我现在主要的问题是:

  • 将OAuth2中的承载令牌替换为OAuth1中的密钥和访问令牌吗?
  • 我不需要密钥和访问权限即可授权rquest?我基于Google开发人员网站本身的示例

为了更加清晰,我将从Google开发者网站中提取的代码修改为适合我的支持者:

// Call this function just once,to initialize the OAuth client.
function initializeOAuthClient() {
  if (typeof OAuth2 === 'undefined') {
    var libUrl = 'https://developers.google.com/google-ads/scripts/docs/examples/oauth20-library';
    throw Error('OAuth2 library not found. Please take a copy of the OAuth2 ' +
        'library from ' + libUrl + ' and append to the bottom of this script.');
  }
  var tokenUrl = 'https://api.twitter.com/oauth2/token';
  authUrlFetch = OAuth2.withClientCredentials(
      tokenUrl,CONSUMER_KEY,CONSUMER_SECRET);
}

function sendTweet(status) {
  var service = accessProtectedResource(SERVICE_UPDATE_URL,"post");
  
  if (service.hasAccess()) {
    var url = 'https://api.twitter.com/1.1/statuses/update.json?include_entities=true&status=' + percentEncode(status);
    var response = service.fetch(url);
    //var result = JSON.parse(response.getContentText());
    
    return response;
  }
}


/**
 * Attempts to access a non-Google API using a constructed service
 * object.
 *
 * If your add-on needs access to non-Google APIs that require OAuth,* you need to implement this method. You can use the OAuth1 and
 * OAuth2 Apps Script libraries to help implement it.
 *
 * @param {String} url         The URL to access.
 * @param {String} method_opt  The HTTP method. Defaults to GET.
 * @param {Object} headers_opt The HTTP headers. Defaults to an empty
 *                             object. The Authorization field is added
 *                             to the headers in this method.
 * @return {HttpResponse} the result from the UrlFetchApp.fetch() call.
 */
function accessProtectedResource(url,method_opt,headers_opt) {
  var service = getOAuthService();
  var maybeAuthorized = service.hasAccess();
  if (maybeAuthorized) {
    // A token is present,but it may be expired or invalid. Make a
    // request and check the response code to be sure.

    // Make the UrlFetch request and return the result.
    var accessToken = service.getAccessToken();
    var method = method_opt || 'post';
    var headers = headers_opt || {};
    headers['Authorization'] =
        Utilities.formatString('Bearer %s',accessToken);
    var resp = UrlFetchApp.fetch(url,{
      'headers': headers,'method' : method,'muteHttpExceptions': true,// Prevents thrown HTTP exceptions.
    });

    var code = resp.getResponseCode();
    if (code >= 200 && code < 300) {
      return resp.getContentText("utf-8"); // Success
    } else if (code == 401 || code == 403) {
       // Not fully authorized for this action.
       maybeAuthorized = false;
    } else {
       // Handle other response codes by logging them and throwing an
       // exception.
       console.error("Backend server error (%s): %s",code.toString(),resp.getContentText("utf-8"));
       throw ("Backend server error: " + code);
    }
  }

  if (!maybeAuthorized) {
    // Invoke the authorization flow using the default authorization
    // prompt card.
    CardService.newAuthorizationException()
        .setAuthorizationUrl(service.getAuthorizationUrl())
        .setResourceDisplayName("Display name to show to the user")
        .throwException();
  }
}

/**
 * Create a new OAuth service to facilitate accessing an API.
 * This example assumes there is a single service that the add-on needs to
 * access. Its name is used when persisting the authorized token,so ensure
 * it is unique within the scope of the property store. You must set the
 * client secret and client ID,which are obtained when registering your
 * add-on with the API.
 *
 * See the Apps Script OAuth2 Library documentation for more
 * information:
 *   https://github.com/googlesamples/apps-script-oauth2#1-create-the-oauth2-service
 *
 *  @return A configured OAuth2 service object.
 */
function getOAuthService() {
  
  return OAuth2.createService('SERVICE_NAME')
      .setAuthorizationBaseUrl('SERVICE_AUTH_URL')
      .setTokenUrl('SERVICE_AUTH_TOKEN_URL')
      .setClientId('CLIENT_ID')
      .setClientSecret('CLIENT_SECRET')
      .setScope('SERVICE_SCOPE_REQUESTS')
      .setCallbackFunction('authCallback')
      .setCache(CacheService.getUserCache())
      .setPropertyStore(PropertiesService.getScriptProperties())
}

/**
 * Boilerplate code to determine if a request is authorized and returns
 * a corresponding HTML message. When the user completes the OAuth2 flow
 * on the service provider's website,this function is invoked from the
 * service. In order for authorization to succeed you must make sure that
 * the service knows how to call this function by setting the correct
 * redirect URL.
 *
 * The redirect URL to enter is:
 * https://script.google.com/macros/d/<Apps Script ID>/usercallback
 *
 * See the Apps Script OAuth2 Library documentation for more
 * information:
 *   https://github.com/googlesamples/apps-script-oauth2#1-create-the-oauth2-service
 *
 *  @param {Object} callbackRequest The request data received from the
 *                  callback function. Pass it to the service's
 *                  handleCallback() method to complete the
 *                  authorization process.
 *  @return {HtmlOutput} a success or denied HTML message to display to
 *          the user. Also sets a timer to close the window
 *          automatically.
 */
function authCallback(callbackRequest) {
  var authorized = getOAuthService().handleCallback(callbackRequest);
  if (authorized) {
    return HtmlService.createHtmlOutput(
      'Success! <script>setTimeout(function() { top.window.close() },1);</script>');
  } else {
    return HtmlService.createHtmlOutput('Denied');
  }
}

/**
 * Unauthorizes the non-Google service. This is useful for OAuth
 * development/testing.  Run this method (Run > resetOAuth in the script
 * editor) to reset OAuth to re-prompt the user for OAuth.
 */
function resetOAuth() {
  getOAuthService().reset();
}

function main() {
  try {
      let result = sendTweet("Este va a ser un gran día!\n https://www.instagram.com/amos_oficialba/");
      Logger.log("Resultado: " + result);
  }
  catch(err) {
    console.log(err["stack"]);
  }
}

解决方法

本地支持已从OAuthConfig中删除,但这并不妨碍您的应用向外部API发出OAuth 1请求。开源库OAuth1 for Apps Script是作为替换库创建的,以防您以前使用OAuthConfig

要使用OAuth1 for Apps脚本库从Google Apps脚本进行鸣叫:

  1. 您需要在Twitter Developer门户中设置回调URL。使用此库时,回调URL始终为https://script.google.com/macros/s/YOUR_SCRIPT_ID/usercallback格式。您将需要用脚本的ID替换YOUR_SCRIPT_ID
  2. 在Google Apps脚本中,转到“文件”菜单,然后选择“项目属性”。记下您的脚本ID。 enter image description here
  3. Twitter Developer portal中,选择您的应用,然后在“身份验证设置”下单击“编辑”。
  4. 添加回调URL,然后在完成后单击“保存”:enter image description here
  5. 返回Google Apps脚本,选择“资源”菜单,然后单击“库”。
  6. 在“库”窗口中,输入OAuth1库的ID 1CXDCY5sqT9ph64fFwSzVtXnbjpSfWdRymafDrtIZ7Z_hwysTY7IIhi7s,然后单击“添加”。
  7. 选择最新版本(撰写本文时为18The Libraries window displaying the OAuth library being selected

完成后,使用此脚本设置有效的Tweet请求。将CONSUMER_KEYCONSUMER_SECRET替换为您应用的API密钥和密钥;将TOKENTOKEN_SECRET替换为用户的访问令牌和访问令牌密钥。

var CONSUMER_KEY = 'your consumer key';
var CONSUMER_SECRET = 'your consumer secret';
var TOKEN = 'your access token';
var TOKEN_SECRET = 'your access token secret';
/**
 * Authorizes and makes a request to the Twitter API.
 */
function run() {
  var service = getService();
  Logger.log(service.getCallbackUrl())
  if (service.hasAccess()) {
    var url = 'https://api.twitter.com/1.1/statuses/update.json';
    var payload = {
      status: 'just setting up my google apps script'
    };
    var response = service.fetch(url,{
      method: 'post',payload: payload
    });
    var result = JSON.parse(response.getContentText());
    Logger.log(JSON.stringify(result,null,2));
  } else {
    var authorizationUrl = service.authorize();
    Logger.log('Open the following URL and re-run the script: %s',authorizationUrl);
  }
} 

function doGet() {
  return HtmlService.createHtmlOutput(ScriptApp.getService().getUrl());
}

/**
 * Reset the authorization state,so that it can be re-tested.
 */
function reset() {
  var service = getService();
  service.reset();
}

/**
 * Configures the service.
 */
function getService() {
  return OAuth1.createService('Twitter')
      // Set the endpoint URLs.
      .setAccessTokenUrl('https://api.twitter.com/oauth/access_token')
      .setRequestTokenUrl('https://api.twitter.com/oauth/request_token')
      .setAuthorizationUrl('https://api.twitter.com/oauth/authorize')

      // Set the consumer key and secret.
      .setConsumerKey(CONSUMER_KEY)
      .setConsumerSecret(CONSUMER_SECRET)

      // Set your user's access token key and secret
      .setAccessToken(TOKEN,TOKEN_SECRET)

      .setCallbackFunction('authCallback')  
}

/**
 * Handles the OAuth callback.
 */
function authCallback(request) {
  var service = getService();
  var authorized = service.handleCallback(request);
  if (authorized) {
    return HtmlService.createHtmlOutput('Success!');
  } else {
    return HtmlService.createHtmlOutput('Denied');
  }
}

或者,您可以使用Google自己的OAuth 1 replacement script来签署OAuth 1请求。您可以在Google Ads script page中找到用法的示例。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...