建造 | 依赖性 |
---|---|
JSON Web 令牌的实现。
这是针对draft-ietf-oauth-json-web-token-08
开发的。它利用node-jws
$ npm 安装 jsonwebtoken
从 v8 到 v9
从 v7 到 v8
(异步)如果提供回调,则使用err
或 JWT 调用回调。
(同步)以字符串形式返回 JsonWebToken
payload
可以是对象文字、缓冲区或表示有效 JSON 的字符串。
请注意,仅当有效负载是对象文字时才会设置
exp
或任何其他声明。不会检查缓冲区或字符串有效负载的 JSON 有效性。
如果
payload
不是缓冲区或字符串,则会使用JSON.stringify
将其强制转换为字符串。
secretOrPrivateKey
是一个字符串(utf-8 编码)、缓冲区、对象或 KeyObject,其中包含 HMAC 算法的秘密或 RSA 和 ECDSA 的 PEM 编码私钥。如果私钥带有密码短语,则可以使用对象{ key, passphrase }
(基于加密文档),在这种情况下,请确保传递algorithm
选项。使用 RSA 算法签名时,最小模数长度为 2048,除非allowInsecureKeySizes 选项设置为 true。低于此大小的私钥将被拒绝并出现错误。
options
:
algorithm
(默认: HS256
)
expiresIn
:以秒或描述时间跨度 vercel/ms 的字符串表示。
例如:
60
、"2 days"
、"10h"
、"7d"
。数值被解释为秒数。如果您使用字符串,请确保提供时间单位(天、小时等),否则默认使用毫秒单位("120"
等于"120ms"
)。
notBefore
:以秒或描述时间跨度 vercel/ms 的字符串表示。
例如:
60
、"2 days"
、"10h"
、"7d"
。数值被解释为秒数。如果您使用字符串,请确保提供时间单位(天、小时等),否则默认使用毫秒单位("120"
等于"120ms"
)。
audience
issuer
jwtid
subject
noTimestamp
header
keyid
mutatePayload
:如果为 true,sign 函数将直接修改有效负载对象。如果您在应用声明之后但在将其编码到令牌之前需要对有效负载进行原始引用,那么这非常有用。
allowInsecureKeySizes
:如果 true 允许模数低于 2048 的私钥用于 RSA
allowInvalidAsymmetricKeyTypes
:如果为 true,则允许与指定算法不匹配的非对称密钥。此选项仅用于向后兼容,应避免使用。
expiresIn
、notBefore
、audience
、subject
、issuer
没有默认值。 这些声明也可以分别通过exp
、nbf
、aud
、sub
和iss
直接在有效负载中提供,但不能同时包含在这两个地方。
请记住exp
、 nbf
和iat
是NumericDate ,请参阅相关的令牌到期时间(exp 声明)
可以通过options.header
对象自定义标头。
除非指定noTimestamp
,否则生成的 jwts 将默认包含iat
(发布于)声明。如果将iat
插入有效负载中,则将使用它将代替真实时间戳来计算其他内容,例如在options.expiresIn
中给定时间跨度的exp
。
默认同步签名 (HMAC SHA256)
var jwt = require('jsonwebtoken');var token = jwt.sign({ foo: 'bar' }, 'shhhhh');
使用 RSA SHA256 同步签名
// 使用 RSA SHA256 进行签名var privateKey = fs.readFileSync('private.key');var token = jwt.sign({ foo: 'bar' }, privateKey, { algorithm: 'RS256' });
异步签名
jwt.sign({ foo: 'bar' }, privateKey, { 算法: 'RS256' }, function(err, token) { console.log(令牌);});
jwt 回溯 30 秒
var old_token = jwt.sign({ foo: 'bar', iat: Math.floor(Date.now() / 1000) - 30 }, 'shhhhh');
JWT 标准定义了过期exp
。过期时间用NumericDate表示:
一个 JSON 数值,表示从 1970-01-01T00:00:00Z UTC 到指定 UTC 日期/时间的秒数,忽略闰秒。 这相当于 IEEE Std 1003.1,2013 版 [POSIX.1] 定义“自纪元以来的秒数”,其中每天精确计算 86400 秒,但可以表示非整数值。 有关一般日期/时间(特别是 UTC)的详细信息,请参阅 RFC 3339 [RFC3339]。
这意味着exp
字段应包含自纪元以来的秒数。
签署具有 1 小时有效期的令牌:
jwt. 符号({ exp: Math.floor(Date.now() / 1000) + (60 * 60), 数据:'foobar'},'秘密');
使用此库生成此类令牌的另一种方法是:
jwt. 符号({ data: 'foobar'}, 'secret', { expiresIn: 60 * 60 });//甚至更好:jwt.sign({ 数据: 'foobar'}, '秘密', { expiresIn: '1h' });
(异步)如果提供回调,函数将异步运行。如果签名有效并且可选的过期时间、受众或颁发者有效,则使用解码后的有效负载调用回调。如果没有,调用时会出现错误。
(同步)如果未提供回调,函数将同步运行。如果签名有效并且可选的过期时间、受众或颁发者有效,则返回解码的有效负载。如果没有,它将抛出错误。
警告:当令牌来自不受信任的来源(例如用户输入或外部请求)时,返回的解码负载应像任何其他用户输入一样对待;请确保进行消毒并仅使用预期的房产
token
是 JsonWebToken 字符串
secretOrPublicKey
是一个字符串(utf-8 编码)、缓冲区或 KeyObject,其中包含 HMAC 算法的秘密或 RSA 和 ECDSA 的 PEM 编码公钥。如果jwt.verify
被异步调用, secretOrPublicKey
可以是一个应该获取秘密或公钥的函数。请参阅下面的详细示例
正如本评论中提到的,还有其他库需要 base64 编码的秘密(使用 base64 编码的随机字节),如果是你的情况,你可以传递Buffer.from(secret, 'base64')
,通过这样做,秘密将被解码使用base64并且令牌验证将使用原始随机字节。
options
algorithms
:包含允许的算法名称的字符串列表。例如, ["HS256", "HS384"]
。
如果未指定,将根据提供的密钥类型使用默认值
秘密 - ['HS256'、'HS384'、'HS512']
rsa - ['RS256','RS384','RS512']
ec-['ES256'、'ES384'、'ES512']
默认 - ['RS256'、'RS384'、'RS512']
audience
:如果您想检查受众 ( aud
),请在此处提供一个值。可以对照字符串、正则表达式或者字符串和/或正则表达式的列表来检查受众。
例如:
"urn:foo"
,/urn:f[o]{2}/
,[/urn:f[o]{2}/, "urn:bar"]
complete
:返回一个带有解码后的{ payload, header, signature }
的对象,而不是仅返回有效负载的通常内容。
issuer
(可选): iss
字段有效值的字符串或字符串数组。
jwtid
(可选):如果您想检查 JWT ID ( jti
),请在此处提供一个字符串值。
ignoreExpiration
:如果true
则不验证令牌的过期时间。
ignoreNotBefore
...
subject
:如果您想检查主题 ( sub
),请在此处提供一个值
clockTolerance
:检查nbf
和exp
声明时容忍的秒数,以处理不同服务器之间的微小时钟差异
maxAge
:令牌仍然有效的最大允许年龄。它以秒或描述时间跨度 vercel/ms 的字符串表示。
例如:
1000
、"2 days"
、"10h"
、"7d"
。数值被解释为秒数。如果您使用字符串,请确保提供时间单位(天、小时等),否则默认使用毫秒单位("120"
等于"120ms"
)。
clockTimestamp
:应用作所有必要比较的当前时间的时间(以秒为单位)。
nonce
:如果您想检查nonce
声明,请在此处提供一个字符串值。它在 Open ID 上用于 ID 令牌。 (开放ID实施说明)
allowInvalidAsymmetricKeyTypes
:如果为 true,则允许与指定算法不匹配的非对称密钥。此选项仅用于向后兼容,应避免使用。
// 验证令牌对称 - 同步var解码= jwt.verify(token, 'shhhhh');console.log(decoded.foo) // bar//验证令牌对称jwt.verify(token, 'shhhhh', function(err) ,解码){ console.log(decoded.foo) // bar});// 无效令牌 - synchronoustry { var解码 = jwt.verify(token, '错误的秘密');} catch(err) { // err}// 无效 tokenjwt.verify(token, '错误的秘密', function(err, 已解码) { // 错误 // 解码 undefined});// 验证令牌非对称var cert = fs.readFileSync('public.pem'); // 获取公钥jwt.verify(token, cert, function(err,已解码) { console.log(decoded.foo) // bar});// 验证受众 var cert = fs.readFileSync('public.pem'); // 获取公钥jwt.verify(token, cert, { Audience: 'urn:foo' }, function(err,已解码) { // 如果受众不匹配,则 err == 无效受众});// 验证颁发者var cert = fs.readFileSync('public.pem'); // 获取公钥jwt.verify(token, cert, { Audience: 'urn:foo', Issuer: 'urn:issuer' }, function(err,已解码) { // 如果颁发者不匹配,err == 无效颁发者});// 验证 jwt idvar cert = fs.readFileSync('public.pem'); // 获取公钥jwt.verify(token, cert, { Audience: 'urn:foo', Issuer: 'urn:issuer', jwtid: 'jwtid' }, function(err,已解码) { // 如果 jwt id 不匹配,则 err == 无效 jwt id});// 验证主题var cert = fs.readFileSync('public.pem'); // 获取公钥jwt.verify(token, cert, { Audience: 'urn:foo', Issuer: 'urn:issuer', jwtid: 'jwtid', subject: 'subject' }, function(err,已解码) { // 如果主题不匹配,则 err == 无效主题});// alg 不匹配var cert = fs.readFileSync('public.pem'); // 获取公钥jwt.verify(token, cert, {算法: ['RS256'] }, function (err, payload) { // if token alg != RS256, err == invalid Signature});// 使用 getKey 回调验证 // 示例使用 https://github.com/auth0/node-jwks-rsa 作为获取密钥的方式。 var jwksClient = require('jwks-rsa');var client = jwksClient({ jwksUri: 'https://sandrino.auth0.com/.well-known/jwks.json'});函数 getKey(标头, 回调){ client.getSigningKey(header.kid, function(err, key) {varsigningKey = key.publicKey || key.rsaPublicKey;callback(null,signingKey); });}jwt.verify(token, getKey, 选项, 函数(err, 解码) { console.log(decoded.foo) // bar});
(同步)返回解码后的有效负载,而不验证签名是否有效。
警告:这不会验证签名是否有效。您不应该将其用于不受信任的消息。您很可能想使用
jwt.verify
代替。
警告:当令牌来自不受信任的来源(例如用户输入或外部请求)时,返回的解码负载应像任何其他用户输入一样对待;请确保进行消毒并仅使用预期的房产
token
是 JsonWebToken 字符串
options
:
json
:即使标头不包含"typ":"JWT"
也对有效负载强制 JSON.parse 。
complete
:返回一个带有解码后的有效负载和标头的对象。
例子
// 获取解码后的有效负载,忽略签名,不需要 SecretOrPrivateKeyvar解码 = jwt.decode(token);// 获取解码后的有效负载和标头var解码 = jwt.decode(token, {complete: true});console.log(decoded. header);console.log(decoded.payload)
验证过程中可能抛出错误。 Error 是验证回调的第一个参数。
如果令牌过期,则会抛出错误。
错误对象:
名称:'TokenExpiredError'
消息:“jwt 已过期”
过期时间:[过期日期]
jwt.verify(token, 'shhhhh', 函数(err, 解码) { if (err) {/* err = { name: 'TokenExpiredError', message: 'jwt 过期', expiredAt: 1408621000 } */ }});
错误对象:
名称:'JsonWebTokenError'
信息:
“无效令牌” - 无法解析标头或有效负载
“jwt 格式错误” - 令牌不具有三个组成部分(由.
分隔)
'需要jwt签名'
“签名无效”
'jwt 观众无效。预期:[选项观众]'
'jwt 发行者无效。预期:[选项发行者]'
'jwt ID 无效。预期:[选项 JWT ID]'
'jwt 主题无效。预期:[选项主题]'
jwt.verify(token, 'shhhhh', 函数(err, 解码) { if (err) {/* err = { name: 'JsonWebTokenError', message: 'jwt 格式错误' } */ }});
如果当前时间早于 nbf 声明,则抛出该异常。
错误对象:
名称:'NotBeforeError'
消息:“jwt 未激活”
日期:2018-10-04T16:10:44.000Z
jwt.verify(token, 'shhhhh', 函数(err, 解码) { if (err) {/* err = { name: 'NotBeforeError', message: 'jwt 未激活', date: 2018-10-04T16:10:44.000Z } */ }});
支持的算法数组。目前支持以下算法。
alg 参数值 | 数字签名或MAC算法 |
---|---|
HS256 | 使用 SHA-256 哈希算法的 HMAC |
HS384 | 使用 SHA-384 哈希算法的 HMAC |
HS512 | 使用 SHA-512 哈希算法的 HMAC |
RS256 | RSASSA-PKCS1-v1_5 使用 SHA-256 哈希算法 |
RS384 | RSASSA-PKCS1-v1_5 使用 SHA-384 哈希算法 |
RS512 | RSASSA-PKCS1-v1_5 使用 SHA-512 哈希算法 |
PS256 | RSASSA-PSS 使用 SHA-256 哈希算法(仅限节点 ^6.12.0 OR >=8.0.0) |
PS384 | RSASSA-PSS 使用 SHA-384 哈希算法(仅限节点 ^6.12.0 OR >=8.0.0) |
PS512 | RSASSA-PSS 使用 SHA-512 哈希算法(仅限节点 ^6.12.0 OR >=8.0.0) |
ES256 | 使用 P-256 曲线和 SHA-256 哈希算法的 ECDSA |
ES384 | 使用 P-384 曲线和 SHA-384 哈希算法的 ECDSA |
ES512 | 使用 P-521 曲线和 SHA-512 哈希算法的 ECDSA |
没有任何 | 不包含数字签名或 MAC 值 |
首先,我们建议您仔细考虑自动刷新 JWT 是否不会在您的系统中引入任何漏洞。
我们不愿意将其作为库的一部分,但是,您可以查看此示例以展示如何实现这一点。除了该示例之外,还有一个问题和拉取请求以获取有关该主题的更多知识。
X.509 证书链未检查
如果您发现错误或有功能请求,请在此存储库问题部分报告。请不要在公共 GitHub 问题跟踪器上报告安全漏洞。负责任的披露计划详细说明了披露安全问题的程序。
授权0
该项目已获得 MIT 许可。有关详细信息,请参阅许可证文件。