计算 oauth 签名

Calculating an oauth signature

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

我一直非常小心地确保我正确地创建了“签名基础字符串”。他们定义它是这样创建的:

(HTTP Method)&(Request URL)&(Normalized Parameters)

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

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

Use the HMAC-SHA1 signature algorithm as defined by the [RFC2104] to sign the request where text is the Signature Base String and key is the concatenated values of the Consumer Secret and Access Secret separated by an '&' character (show '&' even if Access Secret is empty as some methods do not require an Access Token).

The calculated digest octet string, first base64-encoded per [RFC2045], then escaped using the [RFC3986] percent-encoding (%xx) mechanism is the 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 编码,请一些人理智地检查我对此的理解以及我在使用该库的代码中对它的 usage/expressing,我认为这就是我的问题所在是。

这是我的完整代码:

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

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

我得到的回复是:

Invalid signature: oauth_signature 'RWeFME4w2Obzn2x50xsXujAs1yI='

也很清楚

  1. 我没有理解 API
  2. 中提供的说明
  3. 或者我理解了它们但是我没有在我的代码中那样表达它们
  4. 或以上两者
  5. 或者我在某个地方犯了一些我看不到的细微错误

非常感谢您进行完整性检查,这需要一段时间。

好吧...我做到了,但不是我想的那样,我花了几个小时尝试 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,还有使用 angular 的任何人如果您遇到 CORS 相关错误,请像这样开始 chrome:

chromium-browser --disable-web-security - 我在终端上执行此操作 或将该扩展名添加到 windows 上的某些 chrome 快捷方式,作为快速解决方法,希望它能帮助那里的任何人。