#javascript #node.js #jwt
#javascript #node.js #jwt
Вопрос:
Я пытаюсь декодировать JWT id_token
с помощью jwks-rsa и jsonwebtoken, но результат возвращается как undefined
.
Я знаю, что это как-то связано с обратными вызовами и тем фактом, что мне нужно ждать ответа от getKey
функции, но я не могу понять, как структурировать код, чтобы это произошло.
Это то, что у меня есть до сих пор…
function do_thing(properties, context) {
const id_token = "REDACTED";
// Verify using getKey callback
var jwksClient = require('jwks-rsa');
var client = jwksClient({
jwksUri: 'https://REDACTED.com/.well-known/jwks.json'
});
function getKey(header, callback) {
client.getSigningKey(header.kid, function(err, key) {
var signingKey = key.publicKey || key.rsaPublicKey;
callback(null, signingKey);
});
}
var jwt = require('jsonwebtoken');
jwt.verify(id_token, getKey, { algorithms: ['RS256'] }, function(err, decoded) {
if (err) {
console.log(err);
} else {
return decoded;
}
});
const bubble_obj = do_thing();
console.log(bubble_obj); //This is `undefined`
console.log(bubble_obj);
Выводится как undefined
.
Я знаю, что проблема с приведенным выше кодом связана с характером обратных вызовов и асинхронного кода, потому что, если я перемещу console.log
внутренний jwt.verify
вызов, он покажет правильно декодированный токен.
Этот пример смотрите здесь…
function do_thing(properties, context) {
const id_token = "REDACTED";
// Verify using getKey callback
var jwksClient = require('jwks-rsa');
var client = jwksClient({
jwksUri: 'https://REDACTED.com/.well-known/jwks.json'
});
function getKey(header, callback) {
client.getSigningKey(header.kid, function(err, key) {
var signingKey = key.publicKey || key.rsaPublicKey;
callback(null, signingKey);
});
}
var jwt = require('jsonwebtoken');
jwt.verify(id_token, getKey, { algorithms: ['RS256'] }, function(err, decoded) {
if (err) {
console.log(err);
} else {
console.log(decoded); //When moved here, it prints the correctly decoded token
return decoded;
}
});
const bubble_obj = do_thing();
Итак, как мне заставить его вернуть правильно декодированный токен?
Ответ №1:
Вы неправильно обрабатываете асинхронный код. jwt.verify
Метод возвращает обещание, если вы не передаете ему метод обратного вызова.
Если вы используете return jwt.verify(id_token, getKey, { algorithms: ['RS256'] })
внутри do_thing
функции и вызываете ее таким do_thing().then((decodedToken) => console.log(decodedToken))
образом, она должна работать так, как ожидалось.
Комментарии:
1. Теперь это выдает сообщение об ошибке,
JsonWebTokenError: verify must be called asynchronous if secret or public key is provided as a callback"
поэтому я попытался превратитьdo_thing()
функцию в асинхронную функцию и сделал этоreturn await jwt.verify(id_token, getKey, { algorithms: ['RS256'] })
, но это не устранило ошибку. Смотрите рабочий пример здесь: repl.it/join/fqcsbnck-twistedsizzler2. Я обновил код на repl.it . Он использует асинхронную версию
getSigningKey
, и вызывает метод verifyToken в анонимной самозапускающейся функции3. Это действительно помогло бы прояснить ситуацию, если бы вы прочитали об обещаниях . На высоком уровне они позволяют вам работать с асинхронными функциями без необходимости передавать обратные вызовы. Это делает ваш код намного более чистым и читаемым. Функция, которая возвращает a
Promise
, может использоваться либо сawait
его помощью, либо с помощью.then()
Ответ №2:
вам нужно обработать обещание, возвращенное jwt.verify . либо используйте promise.then . или используйте async / await.
async function do_thing(properties, context) {
const id_token = "REDACTED";
// Verify using getKey callback
var jwksClient = require('jwks-rsa');
var client = jwksClient({
jwksUri: 'https://REDACTED.com/.well-known/jwks.json'
});
function getKey(header, callback) {
client.getSigningKey(header.kid, function(err, key) {
var signingKey = key.publicKey || key.rsaPublicKey;
callback(null, signingKey);
});
}
const jwt = require('jsonwebtoken');
return jwt.verify(id_token, getKey, { algorithms: ['RS256'] });
}
const decodedToken = await do_thing();
console.log("decoded token:", decodedToken);
Комментарии:
1. Это не работает, потому
const decodedToken = await do_thing();
что не находится внутри асинхронной функции. Поэтому он выдает ошибку.2. вы должны обработать свою вызывающую функцию, чтобы заставить ее работать.
Ответ №3:
Вы можете использовать обещание для проверки JWT с обратным вызовом JWK и обещать следующим образом. Вам нужно будет обернуть следующее в async
функцию, чтобы использовать результат verify_jwks()
функции:
const token = "REDACTED";
var jwksClient = require('jwks-rsa');
// Creates a JWKS Client with a rate limit that
// limits the number of calls to our JWKS endpoint
var client = new JwksClient({
jwksUri: 'https://REDACTED.com/.well-known/jwks.json',
rateLimit: true,
jwksRequestsPerMinute: 10, // Default Value
cache: true, // Default Value
cacheMaxEntries: 5, // Default value
cacheMaxAge: 600000, // Defaults to 10m
});
// Verifies the JWKS asynchronously, returns Promise
async function verify_jwks() {
function getKey(header, callback) {
// Callback that returns the key the corresponding key[kid]
client.getSigningKey(header.kid, function(err, key) {
const signingKey = key.getPublicKey() || key.publicKey || key.rsaPublicKey;
callback(null, signingKey);
});
}
// Returns a Promise with verification result or error
return new Promise((resolve,reject) =>
jsonwebtoken.verify(token,getKey, {
algorithms: ["HS256", "RS256"]
},
function(err,decoded) {
return err ? reject(err) : resolve(decoded);
}
));
}
let resu<
await verify_jwks()
.then(decoded => result = decoded)
.catch(error => console.log(error));
console.log(result);