Я использую пакет узла oauth-1.0a для реализации OAuth с помощью API Zotero.
Я использую код, найденный в репозитории zotero-oauth-example .
Запуск кода в репозитории, упомянутом выше, работает.Я думаю, что моя реализация не работает, потому что я разделил одну функцию в репо на две функции -> пример репо не обрабатывает перенаправление клиента и обработку обратного вызова.
ЧтоЯ думаю, что проблема заключается в следующем: Я думаю, что создание двух разных объектов OAuth (один шаг 1, другой шаг 3) что-то ломает.Обратите внимание, что я временно сохраняю хеш, созданный на шаге 1 hash_function
, который используется на шаге 3.
Я не знаком с OAuth.Есть ли у вас какие-либо предложения по поводу того, что мне следует попробовать?
1) Запрос токена (сервер)
// omitting includes packages
const tokenRequestConfig = {
url: 'https://www.zotero.org/oauth/request',
method: 'POST',
data: {
oauth_callback: baseURL, // redirect to baseURL
},
},
initZoteroIntegration = async () => {
let oAuthHash;
const oauth = OAuth({
consumer: {
key: process.env.ZOTERO_APP_CLIENT_KEY,
secret: process.env.ZOTERO_APP_CLIENT_SECRET,
},
signature_method: 'HMAC-SHA1',
hash_function(base_string, key) {
oAuthHash = crypto.createHmac('sha1', key).update(base_string).digest('base64');
return oAuthHash;
},
}),
tokenRequestResponse = await fetch('https://www.zotero.org/oauth/request', {
headers: oauth.toHeader(oauth.authorize(tokenRequestConfig)),
method: 'post',
}),
tokenRequestData = await tokenRequestResponse.text(),
obj = {};
tokenRequestData.replace(/([^=&]+)=([^&]*)/g, (m, key, value) => {
obj[decodeURIComponent(key)] = decodeURIComponent(value);
});
const oAuthToken = obj.oauth_token,
oAuthTokenSecret = obj.oauth_token_secret,
url = `https://www.zotero.org/oauth/authorize?oauth_token=${oAuthToken}&library_access=1¬es_access=1&write_access=1&all_groups=write`;
/* the url should be returned to the client */
return ({
url,
oAuthToken,
oAuthTokenSecret,
oAuthHash,
});
};
2) Клиент направляется в приложение Zotero для входа в систему и авторизации разрешений.
3) Token Exchange (сервер)
// omitting includes packages
const confirmIntegration = async ({oAuthToken, oAuthTokenSecret, oAuthVerifier, oAuthHash}) => {
const oauth = OAuth({
consumer: {
key: process.env.ZOTERO_APP_CLIENT_KEY,
secret: process.env.ZOTERO_APP_CLIENT_SECRET,
},
signature_method: 'HMAC-SHA1',
hash_function() {
return oAuthHash;
},
}),
tokenExchangeConfig = {
url: `https://www.zotero.org/oauth/access?oauth_token=${oAuthToken}`,
method: 'POST',
data: {
oauth_verifier: oAuthVerifier,
oauth_callback: baseURL,
},
},
tokenExchangeResponse = await fetch(`https://www.zotero.org/oauth/access?oauth_token=${oAuthToken}`, {
headers: oauth.toHeader(oauth.authorize(tokenExchangeConfig, {
public: oAuthToken,
secret: oAuthTokenSecret,
})),
method: 'post',
}),
tokenExchangeData = await tokenExchangeResponse.text();
try {
const username = tokenExchangeData.match(/username=(\w+)/)[1],
userID = tokenExchangeData.match(/userID=([0-9]+)/)[1],
userAPIKey = tokenExchangeData.match(/oauth_token_secret=([a-zA-Z0-9]+)/)[1];
return {
username,
userID,
userAPIKey,
};
} catch (e) {
// TODO throw some error
return null;
}
};
На шаге «Обмен токенами» я получаю ответ с кодом состояния 401 («Не авторизован»).
tokenExchangeResponse.text()
возвращаетсяoauth_problem=signature_invalid
Вот необработанный вывод:
"https_sig_error=1&z_debug_sbs=POST&https%3A%2F%2Fwww.zotero.org%2Foauth%2Faccess&oauth_consumer_key%3D9a016199db19772cb220%26oauth_nonce%3DDs3iXBVWF4izl1qfX0mk0JXIvZkl7N5o%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1545238813%26oauth_token%3D6f6ade01f30625feeb36%26oauth_verifier%3D02469ed77305b02befd8%26oauth_version%3D1.0&oauth_problem=signature_invalid&debug_sbs=POST&https%3A%2F%2Fwww.zotero.org%2Foauth%2Faccess&oauth_consumer_key%3D9a016199db19772cb220%26oauth_nonce%3DDs3iXBVWF4izl1qfX0mk0JXIvZkl7N5o%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1545238813%26oauth_token%3D6f6ade01f30625feeb36%26oauth_verifier%3D02469ed77305b02befd8%26oauth_version%3D1.0"
* Исправление Хорошо, я нашел решение.Я использую node-cache
для кэширования объекта OAuth в течение ограниченного времени.
Спасибо @tnajdek за разъяснение, что вышеупомянутое использование OAuth было проблемой.