Расчет подписи

Я пытаюсь что-то немного конкретное, а именно, пытаясь вызвать REST API. Я следовал этим инструкциям.

Я очень тщательно следил за тем, чтобы правильно создать "Базовую строку подписи". Они определяют, что это должно быть создано так:

(Метод HTTP)&(Запросить URL)&(Нормализованные параметры)

Вы можете перепроверить, если нужно, в моем коде, но я уверен, что все в порядке.

Проблема, которую я имею, состоит в том, чтобы создать то, что они называют "подписью oauth", и моя не совпадает с их. Они это должны быть созданы так:

Используйте алгоритм подписи HMAC-SHA1, как определено в [RFC2104], чтобы подписать запрос, где текст - это базовая строка подписи, а ключ - объединенные значения секрета потребителя и секрета доступа, разделенные символом "&" (показать "&" даже если секрет доступа пуст, так как некоторые методы не требуют токена доступа).

Вычисленная строка октета дайджеста, сначала закодированная в base64 согласно [RFC2045], затем экранированная с использованием механизма [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. Или я где-то совершил небольшую ошибку, которую не вижу

Я был бы очень признателен за проверку работоспособности, это заняло некоторое время.

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, а также всем, кто использует angular, если вы получаете ошибки, связанные с CORS, просто запустите chrome следующим образом:

chromium-browser --disable-web-security - Я делаю это на терминале или добавляю это расширение к некоторому ярлыку Chrome на Windows, так же как бы быстро обойти, надеюсь, это поможет кому-нибудь там.

Другие вопросы по тегам