使用 NodeJS 验证 Azure AD B2C 中 JWT 的签名
Validating signature of JWT in Azure AD B2C with NodeJS
我正在关注 this article 在我们的 Node.JS 应用程序中实施 Azure B2C。
我取回了 JWT 令牌并尝试验证签名。
使用 jsonwebtoken npm 模块验证我的令牌。
此外,我从 OpenID Connect 元数据端点获得了 public 密钥。它们在 JSON 中,看起来像这样:
{ "keys": [{
"kid": "some kid value",
"nbf": some number,
"use": "sig",
"kty": "RSA",
"e": "AQAB",
"n": "some long key"
}, {
"kid": "some kid value",
"nbf": some number,
"use": "sig",
"kty": "RSA",
"e": "AQAB",
"n": "some long key"
}, {
"kid": "some kid value",
"nbf": some number,
"use": "sig",
"kty": "RSA",
"e": "AQAB",
"n": "some long key"
}]
}
所以当我尝试将 'n' 值从适当的键传递给
jwt.verify(token, 'my n value go here', { algorithms: ['RS256'] }, callbackFunction());
我得到了
Error: PEM_read_bio_PUBKEY failed
我觉得我传递了错误的密钥,而且我找不到任何关于如何使用这个 public 密钥元数据来验证令牌的解释。
文章中唯一有用的行:
A description of how to perform signature validation is outside the scope of this document. Many open source libraries are available to help you with this if you need it.
如何验证签名?
于是,我在Passport-Azure-AD
的源码中找到了答案
- 转到源代码中的 'lib' 文件夹并找到 aadutils.js 文件。
第142行。有一个函数rsaPublicKeyPem(key1, key2)
exports.rsaPublicKeyPem = (modulusB64, exponentB64) => {
const modulus = new Buffer(modulusB64, 'base64');
const exponent = new Buffer(exponentB64, 'base64');
const modulusHex = prepadSigned(modulus.toString('hex'));
const exponentHex = prepadSigned(exponent.toString('hex'));
const modlen = modulusHex.length / 2;
const explen = exponentHex.length / 2;
const encodedModlen = encodeLengthHex(modlen);
const encodedExplen = encodeLengthHex(explen);
const encodedPubkey = `30${encodeLengthHex(
modlen +
explen +
encodedModlen.length / 2 +
encodedExplen.length / 2 + 2
)}02${encodedModlen}${modulusHex}02${encodedExplen}${exponentHex}`;
const derB64 = new Buffer(encodedPubkey,'hex').toString('base64');
const pem = `-----BEGIN RSA PUBLIC KEY-----\n${derB64.match(/.{1,64}/g).join('\n')}\n-----END RSA PUBLIC KEY-----\n`;
return pem;
};
我复制了整个 aadutils 库并使用键调用了这个函数
const aadutils = require('./aadutils');
const jwt = require('jsonwebtoken');
//key is an object from public endpoint. Just follow the tutorial
const pubKey = aadutils.rsaPublicKeyPem(key.n, key.e);
jwt.verify(id_token, pubKey, { algorithms: ['RS256'] }, function(err, decoded) {
//do what you want next
});
已验证我的签名。
我正在关注 this article 在我们的 Node.JS 应用程序中实施 Azure B2C。 我取回了 JWT 令牌并尝试验证签名。 使用 jsonwebtoken npm 模块验证我的令牌。 此外,我从 OpenID Connect 元数据端点获得了 public 密钥。它们在 JSON 中,看起来像这样:
{ "keys": [{
"kid": "some kid value",
"nbf": some number,
"use": "sig",
"kty": "RSA",
"e": "AQAB",
"n": "some long key"
}, {
"kid": "some kid value",
"nbf": some number,
"use": "sig",
"kty": "RSA",
"e": "AQAB",
"n": "some long key"
}, {
"kid": "some kid value",
"nbf": some number,
"use": "sig",
"kty": "RSA",
"e": "AQAB",
"n": "some long key"
}]
}
所以当我尝试将 'n' 值从适当的键传递给
jwt.verify(token, 'my n value go here', { algorithms: ['RS256'] }, callbackFunction());
我得到了
Error: PEM_read_bio_PUBKEY failed
我觉得我传递了错误的密钥,而且我找不到任何关于如何使用这个 public 密钥元数据来验证令牌的解释。 文章中唯一有用的行:
A description of how to perform signature validation is outside the scope of this document. Many open source libraries are available to help you with this if you need it.
如何验证签名?
于是,我在Passport-Azure-AD
的源码中找到了答案- 转到源代码中的 'lib' 文件夹并找到 aadutils.js 文件。
第142行。有一个函数rsaPublicKeyPem(key1, key2)
exports.rsaPublicKeyPem = (modulusB64, exponentB64) => { const modulus = new Buffer(modulusB64, 'base64'); const exponent = new Buffer(exponentB64, 'base64'); const modulusHex = prepadSigned(modulus.toString('hex')); const exponentHex = prepadSigned(exponent.toString('hex')); const modlen = modulusHex.length / 2; const explen = exponentHex.length / 2; const encodedModlen = encodeLengthHex(modlen); const encodedExplen = encodeLengthHex(explen); const encodedPubkey = `30${encodeLengthHex( modlen + explen + encodedModlen.length / 2 + encodedExplen.length / 2 + 2 )}02${encodedModlen}${modulusHex}02${encodedExplen}${exponentHex}`; const derB64 = new Buffer(encodedPubkey,'hex').toString('base64'); const pem = `-----BEGIN RSA PUBLIC KEY-----\n${derB64.match(/.{1,64}/g).join('\n')}\n-----END RSA PUBLIC KEY-----\n`; return pem; };
我复制了整个 aadutils 库并使用键调用了这个函数
const aadutils = require('./aadutils'); const jwt = require('jsonwebtoken'); //key is an object from public endpoint. Just follow the tutorial const pubKey = aadutils.rsaPublicKeyPem(key.n, key.e); jwt.verify(id_token, pubKey, { algorithms: ['RS256'] }, function(err, decoded) { //do what you want next });
已验证我的签名。