计算oauth签名

时间:2015-03-07 00:57:39

标签: rest post oauth hmacsha1 shared-secret

我正在尝试一些特定的东西,即尝试调用REST API。我一直关注这些instructions

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

  

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

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

我遇到的问题是创建他们称之为" oauth签名"而我的并不匹配他们的。它们应该像这样创建:

  

使用[RFC2104]定义的HMAC-SHA1签名算法对请求进行签名,其中text是签名基本字符串,key是消费者秘密和访问密钥的连接值,由'& '字符(显示'&'即使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库。我将签名基本字符串作为文本,然后将我的消费者秘密作为与"&"连接的密钥,我没有访问密钥,并且它不是必需的但是没关系。然后我基于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. 或者我在某处发现了一些我无法看到的微妙错误
  5. 我非常感谢理智检查,这需要一段时间。

1 个答案:

答案 0 :(得分:2)

好吧......我做到了,但不是我认为我最终会这样做的方式,我花了几个小时尝试使用角度然后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 example

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快捷方式,就像快速解决一样,希望它可以帮助任何人。