我一直在成功使用OAuth1.0的邮递员使用API。 现在,我正在构建一个调用该API的API,但是在尝试设置OAuth1.0的javascript中的等效项时遇到了麻烦。 标题看起来像这样:
my_object.__getattribute__
我的问题与 oauth_nonce 和 oauth_signature 有关。
我可以用来生成这两个参数的哈希函数是什么。
感谢您的宝贵时间。
答案 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);
});
我希望它有效!