【问题标题】:Calculating an oauth signature计算 oauth 签名
【发布时间】:2015-05-08 17:31:56
【问题描述】:

我正在尝试一些具体的操作,即尝试调用 REST API。我一直在关注这些instructions

我一直非常小心地确保我正确地创建了“签名基本字符串”。他们将其定义为这样创建:

(HTTP 方法)&(请求 URL)&(规范化参数)

您可以仔细检查我的代码中是否需要,但我非常确定它没问题。

我遇到的问题是创建他们所谓的“oauth 签名”,而我的与他们的不匹配。它们应该像这样创建:

使用 [RFC2104] 定义的 HMAC-SHA1 签名算法对请求进行签名,其中 text 是 Signature Base String,key 是 Consumer Secret 和 Access Secret 的连接值,由“&”字符分隔(显示'&' 即使 Access Secret 为空,因为某些方法不需要访问令牌)。

计算出的摘要八位字节字符串,首先按照 [RFC2045] 进行 base64 编码,然后使用 [RFC3986] 百分比编码 (%xx) 机制进行转义,即 oauth_signature。

我在我的代码中这样表达:

var oauthSignature = CryptoJS.HmacSHA1(signatureBaseString, sharedSecret+"&");
var oauthSignature64 = encodeURIComponent(CryptoJS.enc.Base64.stringify(oauthSignature));
console.log("hash in 64: " + oauthSignature64);

我正在使用 Google 的 CryptoJS 库。我将签名基本字符串作为文本,然后将我的消费者机密作为与“&”连接的密钥,我没有访问密钥,它不是必需的,但没关系。然后我对该哈希的结果进行base 64编码,然后我对其进行URI编码,请一些人理智地检查我对它的理解以及我在使用这个库的代码中对它的使用/表达,我认为这就是我的问题所在。

这是我的完整代码:

var fatSecretRestUrl = "http://platform.fatsecret.com/rest/server.api";

var d = new Date();
var sharedSecret = "xxxx";
var consumerKey = "xxxx";

//this is yet another test tyring to make this thing work
var baseUrl = "http://platform.fatsecret.com/rest/server.api?";
var parameters = "method=food.search&oauth_consumer_key="+consumerKey+"&oauth_nonce=123&oauth_signature_method=HMAC-SHA1&oauth_timestamp="+getTimeInSeconds()+"&oauth_version=1.0&search_expression=banana";
var signatureBaseString = "POST&" + encodeURIComponent(baseUrl) + "&" + encodeURIComponent(parameters);
console.log("signature base string: " + signatureBaseString);
var oauthSignature = CryptoJS.HmacSHA1(signatureBaseString, sharedSecret+"&");
var oauthSignature64 = encodeURIComponent(CryptoJS.enc.Base64.stringify(oauthSignature));
console.log("hash in 64: " + oauthSignature64);

var testUrl = baseUrl+"method=food.search&oauth_consumer_key=xxxx&oauth_nonce=123&oauth_signature="+oauthSignature64+"&oauth_signature_method=HMAC-SHA1&oauth_timestamp="+getTimeInSeconds()+"&oauth_version=1.0&search_expression=banana";
console.log("final URL: " + testUrl);

var request = $http({
  method :"POST",
  url: testUrl
});

我已注意确保我发布的参数按字典顺序排列,并且我非常确定它是正确的。

我得到的回复是:

无效签名:oauth_signature 'RWeFME4w2Obzn2x50xsXujAs1yI='

也很清楚

  1. 我没看懂 API 中提供的说明
  2. 或者我已经理解它们,但我没有在我的代码中以这种方式表达它们
  3. 或两者兼有
  4. 或者我在看不到的地方犯了一些微妙的错误

我非常感谢您进行健全性检查,这需要一段时间。

【问题讨论】:

    标签: rest post oauth hmacsha1 shared-secret


    【解决方案1】:

    嗯......我做到了,但不是我认为我最终会这样做的方式,我花了几个小时用 angular 然后 JQuery 尝试它,最后我尝试了 Node JS 并且它工作了,这里有两个工作示例,一个带有food.get,另一个带有foods.search

    food.get 示例

        var rest              = require('restler'),
        crypto            = require('crypto'),
        apiKey           = 'xxxx',
        fatSecretRestUrl = 'http://platform.fatsecret.com/rest/server.api',
        sharedSecret     = 'xxxx',
        date             = new Date;
        
        // keys in lexicographical order
        var reqObj = {
          food_id: '2395843', // test query
          method: 'food.get',
          oauth_consumer_key: apiKey,
          oauth_nonce: Math.random().toString(36).replace(/[^a-z]/, '').substr(2),
          oauth_signature_method: 'HMAC-SHA1',
          oauth_timestamp: Math.floor(date.getTime() / 1000),
          oauth_version: '1.0'
        };
        
        // make the string...got tired of writing that long thing
        var paramsStr = '';
        for (var i in reqObj) {
          paramsStr += "&" + i + "=" + reqObj[i];
        }
        
        // had an extra '&' at the front
        paramsStr = paramsStr.substr(1);
        
        var sigBaseStr = "GET&"
                         + encodeURIComponent(fatSecretRestUrl)
                         + "&"
                         + encodeURIComponent(paramsStr);
        
        // no access token but we still have to append '&' according to the instructions
        sharedSecret += "&";
        
        var hashedBaseStr  = crypto.createHmac('sha1', sharedSecret).update(sigBaseStr).digest('base64');
        
        // Add oauth_signature to the request object
        reqObj.oauth_signature = hashedBaseStr;
        
        rest.get(fatSecretRestUrl, {
          data: reqObj,
        }).on('complete', function(data, response) {
          console.log(response);
          console.log("DATA: " + data + "\n");
        });
    

    foods.search 示例

        var rest              = require('restler'),
        crypto            = require('crypto'),
        apiKey           = 'xxxx',
        fatSecretRestUrl = 'http://platform.fatsecret.com/rest/server.api',
        sharedSecret     = 'xxxx',
        date             = new Date;
        
        // keys in lexicographical order
        var reqObj = {
          method: 'foods.search',
          oauth_consumer_key: apiKey,
          oauth_nonce: Math.random().toString(36).replace(/[^a-z]/, '').substr(2),
          oauth_signature_method: 'HMAC-SHA1',
          oauth_timestamp: Math.floor(date.getTime() / 1000),
          oauth_version: '1.0',
          search_expression: 'mcdonalds' // test query
        };
        
        // make the string...got tired of writing that long thing
        var paramsStr = '';
        for (var i in reqObj) {
          paramsStr += "&" + i + "=" + reqObj[i];
        }
        
        // had an extra '&' at the front
        paramsStr = paramsStr.substr(1);
        
        var sigBaseStr = "POST&"
                         + encodeURIComponent(fatSecretRestUrl)
                         + "&"
                         + encodeURIComponent(paramsStr);
        
        // again there is no need for an access token, but we need an '&' according to the instructions
        sharedSecret += "&";
        
        var hashedBaseStr  = crypto.createHmac('sha1', sharedSecret).update(sigBaseStr).digest('base64');
        
        // Add oauth_signature to the request object
        reqObj.oauth_signature = hashedBaseStr;
        
        rest.post(fatSecretRestUrl, {
          data: reqObj,
        }).on('complete', function(data, response) {
          console.log(response);
          console.log("DATA: " + data + "\n");
        });
    

    真的很抱歉任何使用 Angular 或 JQuery 的人,如果我有一两分钟的空闲时间,我会尝试使用 angular,如果您遇到与 CORS 相关的错误,任何使用 angular 的人都可以像这样启动 chrome:

    chromium-browser --disable-web-security - 我在终端上执行此操作 或者将该扩展添加到 Windows 上的某个 chrome 快捷方式中,作为一种快速解决方法,希望它可以帮助任何人。

    【讨论】:

      猜你喜欢
      • 2019-08-25
      • 1970-01-01
      • 2012-08-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-20
      • 2023-03-09
      • 2013-04-09
      相关资源
      最近更新 更多