计算oauth签名 [英] Calculating an oauth signature

查看:100
本文介绍了计算oauth签名的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试一些特定的东西,即尝试调用REST API.我一直在遵循这些说明.

我一直非常小心,以确保正确创建签名基本字符串".他们将其定义为像这样创建:

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

您可以再次检查是否需要在我的代码中,但是我非常确定这是可以的.

我遇到的问题是创建他们所谓的"oauth签名",而我的与他们的不匹配.他们应该这样创建:

使用[RFC2104]定义的HMAC-SHA1签名算法对请求进行签名,其中文本是签名基本字符串",密钥是用&"分隔的消费者密码"和访问密码"的并置值.字符(即使访问密码"为空,因为某些方法不需要访问令牌也显示&").

计算得出的摘要八位字节字符串,首先是根据[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. 或者我在看不见的地方犯了一些细微的错误

我真的很感谢您进行健全性检查,这花了一段时间.

解决方案

好吧……我做到了,但不是我认为自己最终会做的那样,我花了几个小时尝试使用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快捷方式中,以作为一种快速的解决方法,希望它对在那里的任何人都有帮助.

I am trying something a little specific, namely trying to call a REST API. I have been following these instructions.

I have been very careful to ensure that I am creating the "Signature base string" correctly. They define it to be created like this:

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

You can double check if need be in my code, but I am very sure that it is fine.

The problem that I am having is creating what they call the "oauth signature" and mine isn't matching theirs. They it should be created like this:

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.

I express this in my code like so:

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

I am using Google's CryptoJS library. I take the signature base string as the text, I then take my consumer secret as the key concatenated with "&", I have no Access key and it isn't required but that is OK. I then base 64 encode the result of that hash, after which I URI encode it, please could some guys sanity check my understanding of that and my usage/expressing of it in code using this library, I think this is where my problem is.

Here is my full code:

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

I have taken care to ensure that the parameters that I am posting are in lexicographical order and I am very sure that it is correct.

The response that I am getting back is:

Invalid signature: oauth_signature 'RWeFME4w2Obzn2x50xsXujAs1yI='

So clearly either

  1. I haven't understood the instructions provided in the API
  2. Or I have understood them but I haven't expressed them in that way in my code
  3. Or both of the above
  4. Or I have made some subtle mistake somewhere that I can't see

I would really appreciate a sanity check, this has taken a while.

解决方案

well...I did it, but not the way that I thought I would end up doing it, I spent hours trying it out with angular then JQuery, then finally I tried Node JS and it worked, here are two working examples, one with food.get and another with foods.search

food.get 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 = {
  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");
});

really sorry to anyone using Angular or JQuery, if I ever have a spare minute or two I will try it with angular, also anyone using angular if you get CORS related errors just start chrome like this:

chromium-browser --disable-web-security - I do this on terminal or add that extension to some chrome shortcut on windows, just as a quick work around, hope it helps anybody out there.

这篇关于计算oauth签名的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆