正在node.js中验证JWT
Validating a JWT in node.js
我正试图基于此示例(在.NET中编写)在node.js中解析和验证JWT令牌:https://github.com/liveservices/LiveSDK/blob/master/Samples/Asp.net/AuthenticationTokenSample/JsonWebToken.cs
这是我的节点js javascript,用于验证令牌:
var validateSignature = function(key, claims, envelope, signature) {
var hasher = crypto.createHash('sha256');
hasher.update(key + "JWTSig");
var key = hasher.digest('binary');
var hmac = crypto.createHmac('sha256', key);
hmac.update(envelope + '.' + claims);
var out = hmac.digest('base64');
console.log(out);
console.log(signature);
console.log(out === signature);
}
现在,非常奇怪的是——它几乎奏效了。以下是三个console.log语句的输出:
pEwNPJ+LUHBdvNx631UzdyVhPFUOvFY8jG3x/cP81FE=
pEwNPJ-LUHBdvNx631UzdyVhPFUOvFY8jG3x_cP81FE
false
在我看来,除了+-/_=之外,散列都是一样的,这似乎很可疑
有人发现我的错误了吗?与我的base64编码有关。
更新
我又玩了一些,这里的base64编码似乎有点奇怪。节点js中的以下代码:
console.log(signature);
var b = new Buffer(signature, 'base64');
console.log(b.toString('base64'));
收益率:
pEwNPJ-LUHBdvNx631UzdyVhPFUOvFY8jG3x_cP81FE
pEwNPJLUHBdvNx631UzdyVhPFUOvFY8jG3xcP81F
这看起来很奇怪,对吧?
感谢Timothy Meade的评论并将我推向正确的方向。
节点的缓冲区类型生成带有+、/和=的标准Base64
这里提到了一个URL安全的base64编码:http://en.wikipedia.org/wiki/Base64
它将+替换为-,/替换为_,并且=是可选的。QueryString(d'uh)上传递的令牌是URL安全版本。因此产生了差异。
代码由一个简单的修复
out = out.replace('+','-').replace('/','_').replace('=','');
我不久前写了这个库,我想您可以使用其中的一些代码。它应该同时在node.js和现代浏览器中运行。
- javascript的JWT库
这不是您尝试使用的确切方法,但我相信这是在NodeJS中验证JWT的首选方法。请注意,我使用NPM base64url
库在base64Url(JWT的默认编码)和base64
(NodeJS对验证函数的期望)之间进行转换。
还要注意,您需要一个公用和专用密钥对来分别进行签名和验证。我在这篇文章的底部包含了用于签署和验证JWT的私钥和公钥。
const base64 = require('base64url');
const crypto = require('crypto');
const verifyFunction = crypto.createVerify('RSA-SHA256');
const fs = require('fs');
// The sample JWT from https://jwt.io/
const JWT = 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.POstGetfAytaZS82wHcjoTyoqhMyxXiWdR7Nn7A29DNSl0EiXLdwJ6xC6AfgZWF1bOsS_TuYI3OG85AmiExREkrS6tDfTQ2B3WXlrr-wp5AokiRbz3_oB4OxG-W9KcEEbDRcZc0nH3L7LzYptiy1PtAylQGxHTWZXtGz4ht0bAecBgmpdgXMguEIcoqPJ1n3pIWk_dUZegpqx0Lka21H6XxUTxiy8OcaarA8zdnPUnV6AmNP3ecFawIFYdvJB_cm-GvpCSbr8G8y_Mllj8f4x9nBH8pQux89_6gUY618iYv7tuPWBFfEbLxtF2pZS6YC1aSfLQxeNe8djT9YjpvRZA';
// This just gets the value of the public key (same as the one at bottom of this post)
const PUB_KEY = fs.readFileSync(__dirname + '/id_rsa_pub.pem', 'utf8');
// Split the JWT by `.` to get each part
const jwtHeader = JWT.split('.')[0];
const jwtPayload = JWT.split('.')[1];
const jwtSignature = JWT.split('.')[2];
// We only need the first two pieces to verify
verifyFunction.write(jwtHeader + '.' + jwtPayload);
verifyFunction.end();
// IMPORTANT: NodeJS expects base64 format, not base64url format!
const jwtSignatureBase64 = base64.toBase64(jwtSignature);
// IMPORTANT: You need to specify that the `jwtSignatureBase64` data is base64 format,
// otherwise, it will default to Buffer format and return false
const signatureIsValid = verifyFunction.verify(PUB_KEY, jwtSignatureBase64, 'base64');
console.log(signatureIsValid); // true
下面的密钥来自这里提到的JWT示例。
私钥:
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAnzyis1ZjfNB0bBgKFMSvvkTtwlvBsaJq7S5wA+kzeVOVpVWw
kWdVha4s38XM/pa/yr47av7+z3VTmvDRyAHcaT92whREFpLv9cj5lTeJSibyr/Mr
m/YtjCZVWgaOYIhwrXwKLqPr/11inWsAkfIytvHWTxZYEcXLgAXFuUuaS3uF9gEi
NQwzGTU1v0FqkqTBr4B8nW3HCN47XUu0t8Y0e+lf4s4OxQawWD79J9/5d3Ry0vbV
3Am1FtGJiJvOwRsIfVChDpYStTcHTCMqtvWbV6L11BWkpzGXSW4Hv43qa+GSYOD2
QU68Mb59oSk2OB+BtOLpJofmbGEGgvmwyCI9MwIDAQABAoIBACiARq2wkltjtcjs
kFvZ7w1JAORHbEufEO1Eu27zOIlqbgyAcAl7q+/1bip4Z/x1IVES84/yTaM8p0go
amMhvgry/mS8vNi1BN2SAZEnb/7xSxbflb70bX9RHLJqKnp5GZe2jexw+wyXlwaM
+bclUCrh9e1ltH7IvUrRrQnFJfh+is1fRon9Co9Li0GwoN0x0byrrngU8Ak3Y6D9
D8GjQA4Elm94ST3izJv8iCOLSDBmzsPsXfcCUZfmTfZ5DbUDMbMxRnSo3nQeoKGC
0Lj9FkWcfmLcpGlSXTO+Ww1L7EGq+PT3NtRae1FZPwjddQ1/4V905kyQFLamAA5Y
lSpE2wkCgYEAy1OPLQcZt4NQnQzPz2SBJqQN2P5u3vXl+zNVKP8w4eBv0vWuJJF+
hkGNnSxXQrTkvDOIUddSKOzHHgSg4nY6K02ecyT0PPm/UZvtRpWrnBjcEVtHEJNp
bU9pLD5iZ0J9sbzPU/LxPmuAP2Bs8JmTn6aFRspFrP7W0s1Nmk2jsm0CgYEAyH0X
+jpoqxj4efZfkUrg5GbSEhf+dZglf0tTOA5bVg8IYwtmNk/pniLG/zI7c+GlTc9B
BwfMr59EzBq/eFMI7+LgXaVUsM/sS4Ry+yeK6SJx/otIMWtDfqxsLD8CPMCRvecC
2Pip4uSgrl0MOebl9XKp57GoaUWRWRHqwV4Y6h8CgYAZhI4mh4qZtnhKjY4TKDjx
QYufXSdLAi9v3FxmvchDwOgn4L+PRVdMwDNms2bsL0m5uPn104EzM6w1vzz1zwKz
5pTpPI0OjgWN13Tq8+PKvm/4Ga2MjgOgPWQkslulO/oMcXbPwWC3hcRdr9tcQtn9
Imf9n2spL/6EDFId+Hp/7QKBgAqlWdiXsWckdE1Fn91/NGHsc8syKvjjk1onDcw0
NvVi5vcba9oGdElJX3e9mxqUKMrw7msJJv1MX8LWyMQC5L6YNYHDfbPF1q5L4i8j
8mRex97UVokJQRRA452V2vCO6S5ETgpnad36de3MUxHgCOX3qL382Qx9/THVmbma
3YfRAoGAUxL/Eu5yvMK8SAt/dJK6FedngcM3JEFNplmtLYVLWhkIlNRGDwkg3I5K
y18Ae9n7dHVueyslrb6weq7dTkYDi3iOYRW8HRkIQh06wEdbxt0shTzAJvvCQfrB
jg/3747WSsf/zBTcHihTRBdAv6OmdhV4/dD5YBfLAkLrd+mX7iE=
-----END RSA PRIVATE KEY-----
公钥:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnzyis1ZjfNB0bBgKFMSv
vkTtwlvBsaJq7S5wA+kzeVOVpVWwkWdVha4s38XM/pa/yr47av7+z3VTmvDRyAHc
aT92whREFpLv9cj5lTeJSibyr/Mrm/YtjCZVWgaOYIhwrXwKLqPr/11inWsAkfIy
tvHWTxZYEcXLgAXFuUuaS3uF9gEiNQwzGTU1v0FqkqTBr4B8nW3HCN47XUu0t8Y0
e+lf4s4OxQawWD79J9/5d3Ry0vbV3Am1FtGJiJvOwRsIfVChDpYStTcHTCMqtvWb
V6L11BWkpzGXSW4Hv43qa+GSYOD2QU68Mb59oSk2OB+BtOLpJofmbGEGgvmwyCI9
MwIDAQAB
-----END PUBLIC KEY-----
- 正在验证8个真/假复选框或复选框中的2个
- 借助asp.net验证或java脚本对多个文本进行验证
- 使用用户名和密码使用node js,AngularJs和JWT进行身份验证
- 如何将 JWT 身份验证与 ACL 混合使用
- 如何在节点中使用 x.509 证书验证 JWT 令牌
- 使用护照-jwt 对节点 API 进行身份验证
- 刷新时的 JWT 角度身份验证
- 使用 jwt 和套接字 io 的身份验证流
- 正在node.js中验证JWT
- 如何将JWT身份验证与Web API集成
- 使用jwt保护api密钥,无需身份验证
- 如何使用Angular JS和JWT验证用户
- 我需要验证jwt吗?
- jsrsign:不能用PEM RSA公钥验证JWT
- 实现无CSRF JWT身份验证的安全方法
- 节点快速通行证(JWT) -验证后回调
- JSON Web令牌(JWT)-验证客户端
- Angular2路由可以使用用户角色参数激活和身份验证(JWT)
- 护照-JWT 验证未触发回调
- 无法验证ID令牌:jwt.Split不是一个函数