Javascript 签约JWT-我做错了吗?
出于教育目的,我正在尝试用JavaScript制作一个JWT生成器。有一个工具可以创建和/或验证JWT 我正在努力使我的结果与验证器的结果相匹配。问题是签名 这是我的密码:Javascript 签约JWT-我做错了吗?,javascript,jwt,Javascript,Jwt,出于教育目的,我正在尝试用JavaScript制作一个JWT生成器。有一个工具可以创建和/或验证JWT 我正在努力使我的结果与验证器的结果相匹配。问题是签名 这是我的密码: function base64url(input) { return btoa(typeof input === 'string' ? input : JSON.stringify(input)) .replace(/=+$/, '') .replace(/\+/g, '-')
function base64url(input) {
return btoa(typeof input === 'string' ? input : JSON.stringify(input))
.replace(/=+$/, '')
.replace(/\+/g, '-')
.replace(/\//g, '_');
}
const JWT = {
encode(header, payload, secret) {
const unsigned = [base64url(header), base64url(payload)].join('.');
return [unsigned, base64url(sha256.hmac(secret, unsigned))].join('.');
}
};
为了加密HMACSHA256,我使用了带有SHA256.HMAC(key,value)
prototype的库。我将它与在线工具进行了比较,结果很好
现在,我用以下代码测试它:
const jwt = JWT.encode(
{
alg: 'HS256',
typ: 'JWT'
},
123,
'xxx'
);
我得到的结果是:
EYJHBGCOIJIUZI1NIISINR5CCI6IKPXVCj9.MTIz.NzhlNTFmYzUxOGQ2YjNlZDFiOTM0ZGRhOTUwNDFmMzEwMzdlNmZkZWRhNGFlMjdlNDU3ZTZhNWRhYjQ1YzFiMQ
另一方面,结果是:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.MTIz.eOUfxRjWs-0BK03ALQFMQN-b97aSuJ-RX5qXatFwbE
如您所见,JWT的三个块中的两个在我的结果和结果中是相同的。签名是不同的,如果你问我,它生成的签名是惊人的短。该工具还将我自己的JWT标记为无效
我使用在线HMAC SHA256生成器进行了检查,我的代码似乎创建了一个有效的签名,因此:
base64url(sha256.hmac('xxx', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.MTIz')) ===
'NzhlNTFmYzUxOGQ2YjNlZDFiOTM0ZGRhOTUwNDFmMzEwMzdlNmZkZWRhNGFlMjdlNDU3ZTZhNWRhYjQ1YzFiMQ'
只是坏了还是用其他方法做的?我不会说你做错了,但你错过了一个小但重要的细节。 来自的结果是正确的,您计算的散列也正确。但是使用哈希创建的签名不正确 使用
sha256.hmac(secret,unsigned)
计算的哈希值是一个大数字,但函数的返回值是该大数字的十六进制字符串表示形式。对于签名,您需要对原始数字进行base64url编码,而不是它的字符串表示形式
我修改了您的代码,以便将哈希值直接编码到base64url(node.js版本):
或者,如果您不使用node.js,您可以改为使用它(正如Robo Robok所建议的):
结果是一个令牌,它与使用以下方法创建的令牌相同:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.MTIz.eOUfxRjWs-0BK03ALQFMQN-b97aSuJ-RX5qXatFwbE
另请参见,其中我解释了比较不同工具结果的步骤。我也想知道。它只发生在对称类型
const JWT = {
encode(header, payload, secret) {
const unsigned = [base64url(header), base64url(payload)].join('.');
const hash = sha256.hmac(secret, unsigned);
console.log(hash);
var signature = new Buffer.from(hash, 'hex').toString('base64').replace(/\+/g,'-').replace(/\=+$/m,'');
return [unsigned, signature].join('.');
}
};
const JWT = {
encode(header, payload, secret) {
const unsigned = [base64url(header), base64url(payload)].join('.');
return [unsigned, base64url(sha256.hmac(secret, unsigned).replace(/\w{2}/g, byte => String.fromCharCode(parseInt(byte, 16))))].join('.');
}
};