Node.js中的OAuth1.0标头

时间:2019-05-31 16:50:18

标签: javascript node.js api oauth backend

我一直在成功使用OAuth1.0的邮递员使用API。 现在,我正在构建一个调用该API的API,但是在尝试设置OAuth1.0的javascript中的等效项时遇到了麻烦。 标题看起来像这样:

my_object.__getattribute__

我的问题与 oauth_nonce oauth_signature 有关。 我可以用来生成这两个参数的哈希函数是什么。
感谢您的宝贵时间。

4 个答案:

答案 0 :(得分:3)

我能够找到Axios的解决方案。我创建了一个OauthHelper类来生成Authorization标头:

const crypto = require('crypto');
const oauth1a = require('oauth-1.0a');

const CONSUMERKEY = '<consumerKey>';
const CONSUMERSECRET = '<consumerSecret>';
const TOKENKEY = '<tokenKey>';
const TOKENSECRET = '<tokenSecret>';

class Oauth1Helper {
    static getAuthHeaderForRequest(request) {
        const oauth = oauth1a({
            consumer: { key: CONSUMERKEY, secret: CONSUMERSECRET },
            signature_method: 'HMAC-SHA1',
            hash_function(base_string, key) {
                return crypto
                    .createHmac('sha1', key)
                    .update(base_string)
                    .digest('base64')
            },
        })

        const authorization = oauth.authorize(request, {
            key: TOKENKEY,
            secret: TOKENSECRET,
        });

        return oauth.toHeader(authorization);
    }
}

module.exports = Oauth1Helper;

然后我就可以通过Axios在需要的地方发布帖子了

const request = {
    url: 'https://api-domain.com',
    method: 'POST',
    body: {
        "uniqueId": 1234
    }
};

const authHeader = Oauth1Helper.getAuthHeaderForRequest(request);

return await axios.post(
    request.url,
    request.body,
    { headers: authHeader });

答案 1 :(得分:0)

这是一个不需要包的。

您需要 makeHeader(consumer, token, request),它适用于 Node 的 https.request,但也适用于 Axios。

const crypto = require('crypto');
const { stringify: qStringify } = require('querystring');
const { httpOptions, fetch } = require('./fetch');

function nonce() {
  return crypto.randomBytes(16).toString('hex');
}

function sign(baseStr, key) {
  return crypto.createHmac('sha1', key).update(baseStr).digest('base64');
}

function percentEncode(str) {
  const notEscapedRe = /[!'()*]/g;
  return encodeURIComponent(str).replace(notEscapedRe, (c) => `%${c.charCodeAt(0).toString(16)}`);
}

function makeObjStr(parameters, quote = '"', split = ',') {
  const ordered = Object.fromEntries(Object.entries(parameters).sort());
  return Object.entries(ordered).map(([key, value]) => `${percentEncode(key)}=${quote}${percentEncode(value)}${quote}`).join(split);
}

function authHeader(parameters) {
  return { Authorization: `OAuth ${makeObjStr(parameters)}` };
}

function makeHeader(consumer, token, request) {
  const oauthData = {
    oauth_consumer_key: consumer.key,
    oauth_token: token.key,
    oauth_nonce: nonce(),
    oauth_signature_method: 'HMAC-SHA1',
    oauth_timestamp: Math.floor(Date.now() / 1000),
    oauth_version: '1.0',
  };
  const baseStr = [
    request.method.toUpperCase(),
    percentEncode(request.url),
    percentEncode(makeObjStr({ ...request.data, ...oauthData }, '', '&')),
  ].join('&');
  const signingKey = [percentEncode(consumer.secret), percentEncode(token.secret)].join('&');
  return authHeader({
    ...oauthData,
    oauth_signature: sign(baseStr, signingKey),
  });
}

function oAuth1Fetch({
  consumer, token, hostname, path, query = {},
}) {
  const request = {
    method: 'GET',
    url: `https://${hostname}${path}`,
    data: query,
  };
  return fetch({
    ...httpOptions,
    headers: makeHeader(consumer, token, request),
    hostname,
    path: `${path}?${qStringify(query)}`,
  });
}

module.exports = {
  oAuth1Fetch,
};

这是我的fetch

const { Agent, request } = require('https');

const httpOptions = {
  agent: new Agent({ keepAlive: true }),
  'User-Agent': `AWS Lambda Node/${process.version} surflog.app`,
  // Accept: 'application/json',
};

function fetch(options) {
  return new Promise((resolve, reject) => {
    const req = request(options, (res) => {
      const data = [];
      res.on('data', (chunk) => data.push(chunk));
      res.on('end', () => {
        const result = Buffer.concat(data).toString();
        console.log(res.statusCode);
        if (res.statusCode >= 200 && res.statusCode < 300) {
          resolve(result);
        } else {
          reject(result);
        }
      });
    });
    req.setTimeout(6000, (err) => {
      console.warn(err);
      console.warn('Timeout', options.hostname);
    });
    req.on('error', reject);
    req.end();
  });
}

module.exports = {
  httpOptions,
  fetch,
};

示例:

oAuth1Fetch({
  consumer: {
    key: 'xyz',
    secret: 'xyz',
  },
  token: {
    key: 'xyz',
    secret: 'xyz',
  },
  hostname: 'apis.garmin.com',
  path: '/wellness-api/rest/backfill/activities',
  query: {
    summaryStartTimeInSeconds: 1609459200,
    summaryEndTimeInSeconds: 1609459200 + 7776000,
  },
}).then(console.log).catch(console.error);

答案 2 :(得分:-1)

我能够解决此问题,而不是通过编码哈希函数,而是通过使用Request进行请求来解决,就像您可以在该线程中进行的那样: How to call the API using OAuth 1.0?

事实是我正在使用Axios,但没有找到如何使用OAuth1.0的解决方案。 使用“请求”,您可以使用:

    request.get('https://api.twitter.com/1.1/users/show.json', {
  oauth:{
    consumer_key:'...',
    consumer_secret:'...',
    token:'...',
    token_secret:'...'
  }}, function (err, res, body) {})

如我所链接的帖子所述。

答案 3 :(得分:-1)

这是对 Greg Van Gorp 之前提出的解决方案的更新,但使用了 Crypto-JS。由于加密已被弃用。

const crypto = require('crypto-js');
const oauth1a = require('oauth-1.0a');

const CONSUMERKEY = '<consumerKey>';
const CONSUMERSECRET = '<consumerSecret>';

class Oauth1Helper {
  static getAuthHeaderForRequest(request) {
    const oauth = oauth1a({
      consumer: {key: CONSUMERKEY, secret: CONSUMERSECRET},
      signature_method: 'HMAC-SHA1',
      hash_function(base_string, key) {
        return crypto.algo.HMAC
          .create(crypto.algo.SHA1, key)
          .update(base_string)
          .finalize()
          .toString(crypto.enc.Base64);
      },
    });

    const authorization = oauth.authorize(request);

    return oauth.toHeader(authorization);
  }
}

module.exports = Oauth1Helper;

我提出的解决方案略有不同,因为它使用的 API 不需要令牌,但我明白只传递令牌应该没有问题,这些在 oauth1a.authorize 方法中是可选的。

请求:

const request = {
         url: 'https://api-domain.com',
         method: 'POST',
         body: {
           someData: '1234',
         },
      };

const authHeader = Oauth1Helper.getAuthHeaderForRequest(request);

axios
  .post(request.url, request.body, {headers: authHeader})
  .then(res => {
     console.log(res);
  })
  .catch(err => {
     console.log(err);
  });

我希望它有效!