2

我需要通过 oauth 1.0 向 500px api 发出经过身份验证的请求。我正在遵循本指南并以几种不同的方式实现了所描述的工作流程,但我不断得到statusCode: 401....

所以这里是应该如何构造 OAuth 请求: 在此处输入图像描述

这是我到目前为止所尝试的:

尝试#1:

likePhoto (id) {
  let crypto = Npm.require('crypto'),
    consumerKey = '-',
    consumerSecret = '-',
    accessToken = Meteor.user().services.Fivehundredpx.accessToken,
    accessTokenSecret = Meteor.user().services.Fivehundredpx.accessTokenSecret,

    url  = 'https://api.500px.com/v1/photos/231034201/vote?vote=1',
    date = new Date,
    method = 'POST';


  // Note that the keys are in alphabetical order
  let reqObj = {
    oauth_consumer_key: consumerKey,
    oauth_nonce: Math.random().toString(36).replace(/[^a-z]/, '').substr(2),
    oauth_signature_method: 'HMAC-SHA1',
    oauth_timestamp: Math.floor(date.getTime() / 1000),
    oauth_token: accessToken,
    oauth_version: '1.0'
  };

  // construct a param=value& string and uriEncode
  let paramsStr = '';
  for (let i in reqObj) {
    paramsStr += "&" + i + "=" + reqObj[i];
  }

  // yank off that first "&"
  paramsStr = paramsStr.substr(1);

  let sigBaseStr = method + "&" + encodeURIComponent(url) + "&" + encodeURIComponent(paramsStr);

  consumerSecret += "&" + accessTokenSecret;

  let hashedBaseStr  = crypto.createHmac('sha1', consumerSecret).update(sigBaseStr).digest('base64');

  // Add oauth_signature to the request object
  reqObj.oauth_signature = encodeURIComponent(hashedBaseStr);

  let authorization = 'OAuth ';
  for (let i in reqObj) {
    authorization += i + '="'+ reqObj[i] + '",';
  }

  console.log(authorization);
  Meteor.http.call(method, url,
    {headers: {
      Authorization: authorization,
    }},
    function (error, result) {
      console.log(result || error);
    });
}

尝试#2:

likePhoto (id) {
  const oauthSignature = require('oauth-signature');
  let date = new Date;
  let httpMethod = 'POST',
    url = 'https://api.500px.com/v1/photos/231034201/vote?vote=1',
    parameters = {
      oauth_consumer_key : '',
      oauth_nonce : Math.random().toString(36).replace(/[^a-z]/, '').substr(2),
      oauth_signature_method : 'HMAC-SHA1',
      oauth_timestamp : Math.floor(date.getTime() / 1000),
      oauth_token : Meteor.user().services.Fivehundredpx.accessToken,
      oauth_version : '1.0',
    },
    consumerSecret = '',
    tokenSecret = Meteor.user().services.Fivehundredpx.accessTokenSecret,

    // generates a RFC 3986 encoded, BASE64 encoded HMAC-SHA1 hash
    encodedSignature = oauthSignature.generate(httpMethod, url, parameters, consumerSecret, tokenSecret),
    // generates a BASE64 encode HMAC-SHA1 hчash
    signature = oauthSignature.generate(httpMethod, url, parameters, consumerSecret, tokenSecret,
      { encodeSignature: false});


  // construct a param=value& string and uriEncode
  let paramsStr = '';
  for (let i in parameters) {
    paramsStr += "&" + i + "=" + parameters[i];
  }

  // Add oauth_signature to the request object
  parameters.oauth_signature = encodedSignature;

  let authorization = 'OAuth ';
  for (let i in parameters) {
    authorization += i + '="'+ parameters[i] + '",';
  }

  console.log(authorization);
  HTTP.call(httpMethod, url,
    {
      headers: {
        'Authorization': authorization,
      }
    },
    function (error, result) {
      console.log(result || error);
    });
}

尝试#3:

function oAuthBaseString(method, url, params, key, token, timestamp, nonce) {
  return method
    + '&' + percentEncode(url)
    + '&' + percentEncode(genSortedParamStr(params, key, token, timestamp, nonce));
}

function oAuthSigningKey(consumer_secret, token_secret) {
  return consumer_secret + '&' + token_secret;
}

function oAuthSignature(base_string, signing_key) {
  var signature = hmac_sha1(base_string, signing_key);
  return percentEncode(signature);
}


// Percent encoding
function percentEncode(str) {
  return encodeURIComponent(str).replace(/[!*()']/g, (character) => {
    return '%' + character.charCodeAt(0).toString(16);
  });
}


// HMAC-SHA1 Encoding, uses jsSHA lib
var jsSHA = require('jssha');
function hmac_sha1(string, secret) {
  let shaObj = new jsSHA("SHA-1", "TEXT");
  shaObj.setHMACKey(secret, "TEXT");
  shaObj.update(string);
  let hmac = shaObj.getHMAC("B64");
  return hmac;
}


// Merge two objects
function mergeObjs(obj1, obj2) {
  for (var attr in obj2) {
    obj1[attr] = obj2[attr];
  }
  return obj1;
}


// Generate Sorted Parameter String for base string params
function genSortedParamStr(params, key, token, timestamp, nonce)  {
  // Merge oauth params & request params to single object
  let paramObj = mergeObjs(
    {
      oauth_consumer_key : key,
      oauth_nonce : nonce,
      oauth_signature_method : 'HMAC-SHA1',
      oauth_timestamp : timestamp,
      oauth_token : token,
      oauth_version : '1.0'
    },
    params
  );
  // Sort alphabetically
  let paramObjKeys = Object.keys(paramObj);
  let len = paramObjKeys.length;
  paramObjKeys.sort();
  // Interpolate to string with format as key1=val1&key2=val2&...
  let paramStr = paramObjKeys[0] + '=' + paramObj[paramObjKeys[0]];
  for (var i = 1; i < len; i++) {
    paramStr += '&' + paramObjKeys[i] + '=' + percentEncode(decodeURIComponent(paramObj[paramObjKeys[i]]));
  }
  return paramStr;
}

likePhoto (id) {
    const btoa = require('btoa');
    // Get acces keys
    const consumerKey       = '-',
      consumerSecret      = '-',
      accessToken         = Meteor.user().services.Fivehundredpx.accessToken,
      accessTokenSecret   = Meteor.user().services.Fivehundredpx.accessTokenSecret;
    // timestamp as unix epoch
    let timestamp  = Math.round(Date.now() / 1000);
    // nonce as base64 encoded unique random string
    let nonce      = btoa(consumerKey + ':' + timestamp);
    // generate signature from base string & signing key
    let httpMethod = 'POST';
    let baseUrl = 'https://api.500px.com/v1/photos/231034201/vote?vote=1';
    let reqParams = '';
    let baseString = oAuthBaseString(httpMethod, baseUrl, reqParams, consumerKey, accessToken, timestamp, nonce);
    let signingKey = oAuthSigningKey(consumerSecret, accessTokenSecret);
    let signature  = oAuthSignature(baseString, signingKey);
    // return interpolated string
    let authorization = 'OAuth ' +
      'oauth_consumer_key="'  + consumerKey       + '", ' +
      'oauth_nonce="'         + nonce             + '", ' +
      'oauth_signature="'     + signature         + '", ' +
      'oauth_signature_method="HMAC-SHA1", '              +
      'oauth_timestamp="'     + timestamp         + '", ' +
      'oauth_token="'         + accessToken       + '", ' +
      'oauth_version="1.0"';

    console.log(authorization);
    HTTP.call(httpMethod, baseUrl,
      {headers: {
        Authorization: authorization,
      }},
      function (error, result) {
        console.log(result || error);
      });
  }

我正在使用这个api 客户端进行测试,所有请求都运行良好。因此,尽管我使用了类似的工作流程和代码来实现另一个 OAuth 1.0 身份验证请求并且它起作用了,但这应该是我的错误。

错误信息:

{ 
  statusCode: 401,
  content: '',
  headers: 
  { date: 'Mon, 09 Oct 2017 05:27:17 GMT',
    'content-type': 'text/html',
    'transfer-encoding': 'chunked',
    connection: 'close',
    status: '401 Unauthorized',
    'x-xss-protection': '1; mode=block',
    'x-content-type-options': 'nosniff',
    'cache-control': 'no-cache',
    'set-cookie': 
    [ 'device_uuid=4b97d884-b24e-413c-90ee-60d11e7f2ad7; path=/; expires=Fri, 09 Oct 2037 05:27:17 -0000',
    '_hpx1=BAh7B0kiD3Nlc3Npb25faWQGOgZFVEkiJWE2MDVmYmUyZjBkODlmNGFhYmM5MjM5OGEwNjU2NzI5BjsAVEkiCWhvc3QGOwBGIhJhcGkuNTAwcHguY29t--aa2897a2b8ee32b650e0d830d51882e5ac8208cb; domain=.500px.com; path=/; HttpOnly' ],
    'x-request-id': '7e13f562-2525-472c-9b80-9870905e6eea',
    'x-runtime': '0.011553',
    'x-rack-cache': 'invalidate, pass',
    server: 'api20-ovh-bhs'
    },
  data: null 
}
4

1 回答 1

0

我终于弄清楚了这个问题,这是对我有用的代码。

import crypto from 'crypto';
import OAuth from 'oauth-1.0a';

const oauth = OAuth({
    consumer: {
        key: '<YOUR-KEY>',
        secret: '<YOUR-KEY-SECRET>'
    },
    signature_method: 'HMAC-SHA1',
    hash_function: function(base_string, key) {
        return crypto.createHmac('sha1', key).update(base_string).digest('base64');
    }
});

likePhoto: function (id) {
    const future = new Future();
    const requestData = {
      url: `https://api.500px.com/v1/photos/${id}/vote?vote=1`,
      method: 'POST'
    };
    const token = {
      key: Meteor.user().services.Fivehundredpx.accessToken,
      secret: Meteor.user().services.Fivehundredpx.accessTokenSecret
    };
    HTTP.call(requestData.method, requestData.url, {
      headers: oauth.toHeader(oauth.authorize(requestData, token)),
    }, function (error, response) {
      if (error) {
        future.return(error); 
      } else {
        future.return(response);
      }
    });
    return future.wait();
 }

于 2017-10-27T13:13:15.730 回答