2013年2月26日,星期二

使用AdWords脚本对OAuth服务进行身份验证

如今,许多API使用OAuth来使用户进行身份验证并调用其服务。 一个非常受欢迎的例子是 Twitter REST API.  浏览AdWords脚本参考,您会发现,使用AdWords脚本可以做的一件很酷的事情是使用UrlFetchApp从URL提取数据。

因此,我问的问题是“我可以编写脚本以使用OAuth进行身份验证并从Twitter REST API检索数据吗?”

显然,我看过的第一个地方是 OAuthConfig UrlFetchApp的类。 我设置了配置并尝试拨打电话,但始终收到验证错误。 一项小小的研究表明,我并不是唯一遇到此问题的人。 问题源于以下事实:通常,用户需要先通过某种对话框进行身份验证,然后才能访问数据。看到这个例子关于 连接到Picasa网络相册 更多细节。

但是后来我发现 一个帖子 有关某人设法通过在其脚本中重新实现OAuth身份验证系统并使用标准UrlFetchApp.fetch()请求来解决此问题的信息。

我正面临挑战,所以我自己重新创建了它。 原来是很多代码,但是最后,您真正需要担心的唯一事情是从Twitter获取正确的密钥并调用_build_authorization_string()。

谢谢,
拉斯

//-----------------------------------
// Authenticate and Connect to OAuth Service
// Created By: 拉斯 Savage
// FreeAdWordsScripts.com
//-----------------------------------
function main() {
  //Define the Twitter Keys and Secrets
  //More info on obtaining these can be found 在 //dev.twitter.com/docs/auth/tokens-devtwittercom
  var 认证_key_stuff = {
    "consumer_key" : "your consumer key",
    "consumer_secret" : "your consumer secret",
    "access_token" : "your access token",
    "access_token_secret" : "your access token secret"
  };

  // Update this with the REST url you want to 呼叫.  I only tested it with GET
  // but i don't think there is anything stopping a POST request from working.
  var url_stuff = {  
    "http_method" : 'GET',
    "base_url" : "//api.twitter.com/1.1/statuses/user_timeline.json"
  };

  //Add the parameters for the REST url you want to 呼叫.
  var url_param_stuff = {
    "screen_name" : "russellsavage" //hey that's me!
  };
  
  // Don't touch this stuff
  var other_oauth_data = {
    "认证_nonce" : Utilities.base64Encode(Math.random() +
          "secret_sauce" +
          (new Date()).getTime()).replace(/(?!\w)/g, ''),
    "认证_signature_method" : "HMAC-SHA1",
    "认证_timestamp" : Math.round((new Date()).getTime() / 1000.0),
    "认证_version" : "1.0"
  };
  
  // Here is where the magic happens
  var auth_string = _build_authorization_string(oauth_key_stuff,url_stuff,url_param_stuff,other_oauth_data);

  var options = {
    "headers" : { "Authorization" :  auth_string }
  };
    
  var url = _build_url(url_stuff,url_param_stuff);
  var response = UrlFetchApp.fetch(url, options);
  var tweets = JSON.parse(response.getContentText());
  
  //now let's log my amazing tweets!
  for(var tweet in tweets) {
    var t = tweets[tweet];
    Logger.log(t.text);
  }
 
  // HELPER FUNCTIONS BELOW
  
  function _build_url(base_url,param_stuff){
    var url = base_url.base_url;
    if(param_stuff != {}) {
      url += '?';
    }
    for(var key in param_stuff) {
      url += key + "=";
      url += encodeURIComponent(param_stuff[key]);
      url += '&';
    }
    return url.slice(0,-1);
  }
  
  function _build_param_string(auth_keys,url_data,oauth_data) {
    var data_for_param_string = {
      "认证_consumer_key" : auth_keys.consumer_key,
      "认证_nonce" : 认证_data.oauth_nonce,
      "认证_signature_method" : 认证_data.oauth_signature_method,
      "认证_timestamp" : 认证_data.oauth_timestamp,
      "认证_token" : auth_keys.access_token,
      "认证_version" : 认证_data.oauth_version
    };
    
    // 广告 d 广告 ditional url values
    for(var my_key in url_data) { 
      data_for_param_string[my_key] = url_data[my_key]; 
    }
    
    // find and sort the keys for later
    var keys = [];
    for(var key in data_for_param_string) {
      keys.push(key);
    }
    keys.sort();
    
    //finally build and return the param string
    var param_string = "";
    for(var i in keys) {
      param_string += keys[i] + "=" + encodeURIComponent(data_for_param_string[keys[i]]);
      if(i < keys.length - 1) {
        param_string += "&";
      }
    }
    
    return param_string;
  }
  
  function _build_sig_base_string(my_url_stuff,my_param_string) {
    return my_url_stuff.http_method +
      "&" + encodeURIComponent(my_url_stuff.base_url) +
      "&" + encodeURIComponent(my_param_string);
  }
  
  function _build_sigining_key(my_key_stuff) {
    return encodeURIComponent(my_key_stuff.consumer_secret) + 
      "&" + encodeURIComponent(my_key_stuff.access_token_secret);
  }
  
  function _build_oauth_signature(base_string,sign) {
    return Utilities.base64Encode(
      Utilities.computeHmacSignature(
        Utilities.MacAlgorithm.HMAC_SHA_1, 
        base_string, 
        sign
      )
    );
  }
  
  function _build_authorization_string(my_key_stuff,my_url_stuff,my_url_param_stuff,my_oauth_stuff) {
    var param_string = _build_param_string(my_key_stuff,my_url_param_stuff,my_oauth_stuff);
    var sig_base_string = _build_sig_base_string(my_url_stuff,param_string);
    var signing_key = _build_sigining_key(my_key_stuff);
    var 认证_signature = _build_oauth_signature(sig_base_string,signing_key);
    return "OAuth " +
           encodeURIComponent("认证_consumer_key") + '="' + 
             encodeURIComponent(my_key_stuff.consumer_key) + '", ' +
           encodeURIComponent("认证_nonce") + '="' + 
             encodeURIComponent(my_oauth_stuff.oauth_nonce) + '", ' +
           encodeURIComponent("认证_signature") + '="' + 
             encodeURIComponent(oauth_signature) + '", ' +
           encodeURIComponent("认证_signature_method") + '="' + 
             encodeURIComponent(my_oauth_stuff.oauth_signature_method) + '", ' +
           encodeURIComponent("认证_timestamp") + '="' + 
             encodeURIComponent(my_oauth_stuff.oauth_timestamp) + '", ' +
           encodeURIComponent("认证_token") + '="' + 
             encodeURIComponent(my_key_stuff.access_token) + '", ' +
           encodeURIComponent("认证_version") + '="' + 
             encodeURIComponent(my_oauth_stuff.oauth_version) + '"';
    
  }
  
}

4条评论: