如何使用 npm Jose 创建签名的 JWT,然后验证此令牌?
How can I create a signed JWT using npm Jose and then verify this token?
我很难理解如何使用 npm jose 模块 (https://www.npmjs.com/package/jose) 在我的 Node 应用程序中创建和验证签名的 JWT 令牌。我的场景是这样的:我想签署一个经过身份验证的请求来访问资源。我可以为此请求授予令牌成功创建 JWT 声明,该声明尊重“its”和“aud”、“exp”等属性,但我想对其进行签名(也就是说,使用 SignJWT 对象和“sign”方法),以便当它作为请求传回我的服务器时,我可以验证它并授予或拒绝访问权限。
“sign”方法似乎不喜欢我为“key”参数传递的任何东西(我没有传递任何选项——也许我应该传递,但是什么?)。
我正在尝试使用 RSA 密钥对。我想用私钥签名并用 public 密钥验证。对于我的迫切需要,我想我可以改用对称密钥,但我正在考虑其他一些未来的场景,在这些场景中我将需要证书密钥的这种经典 PKCS 关系。无论如何,我不认为这个选择与当前阻碍我进步的障碍有任何关系。
我首先尝试使用 jose/util/generate_key_pair 来创建我的 public/private 对。但是当我去使用密钥时,错误告诉我这不被我的实现支持。所以我转而尝试在我的应用程序之外创建一个“pem”证书并应用它(作为文本),但也失败了。 “sign”方法报告密钥必须是“KeyLike”、“CryptoKey”或“Uint8Array”类型。好吧,UInt8Array(节点缓冲区)没有足够的类型信息:它没有说明缓冲区中的内容,而“KeyLike”是一个模糊的定义,可以忽略。在求助于搜索引擎的神谕之后,我发现我可以使用以下来自 Node API 的 CryptoKey 格式创建密钥对:
crypto.webcrypto.subtle.generateKey(
{
name: 'RSASSA-PKCS1-v1_5',
modulusLength: 2048,
publicExponent: new Uint8Array([1, 0, 1]),
hash: "SHA-256"
},
true,
[‘sign’, ‘verify’]
).then((pair:any) => {
serverInstance.keyPair = pair
})
但是,当我到达签名部分时:
siaToken.sign(serverInstance.keyPair.privateKey).then(signature => {
我收到异常报告
“TypeError:CryptoKey 不支持此操作”
考虑到这可能与 generateKey 的“usages”参数有关,我在那里尝试了各种值,但没有成功。
所以,我很困惑。谁能告诉我如何 (a) 为此目的最好地生成一对密钥以及 (b) 如何将这些密钥应用于 JWT 签名?
我也一直在努力使用 jose
对 JWT 进行签名和验证,但最终能够成功使用 HS256 对称密钥加密。我通过以下步骤制作了它(我使用 jose-node-cjs-runtime
仅用于 Node.js 用例。请随意替换为所需的包。另请注意,我发现这些代码适用于 Node.js 版本 16.7.0, 16.9.0 所以请确保安装了它们中的任何一个。如果你想将这些更改部署到生产环境,那么你还必须确保部署环境具有相同的 Node.js 版本。一个实现这一点的方法是在 package.json
中的 engines
键中提及 Node.js 版本):
添加必需的导入
// library for generating symmetric key for jwt
const { createSecretKey } = require('crypto');
// library for signing jwt
const { SignJWT } = require('jose-node-cjs-runtime/jwt/sign');
// library for verifying jwt
const { jwtVerify } = require('jose-node-cjs-runtime/jwt/verify');
创建 KeyObject
类型的密钥
KeyObject
被 Node.js 推荐用于生成对称、非对称密钥时使用。使用以下代码生成 KeyObject
类型的对称密钥 object 并将其存储在 secretKey
.
中
const secretKey = createSecretKey(process.env.JWT_SECRET, 'utf-8');
用足够长的字符串替换process.env.JWT_SECRET
。它需要足够长(使用长度至少为 32 的字符串)否则在签署 JWT 时会抛出以下错误:HS256 requires symmetric keys to be 256 bits or larger
签署 JWT
(async () => {
const token = await new SignJWT({ id: '12345' }) // details to encode in the token
.setProtectedHeader({ alg: 'HS256' }) // algorithm
.setIssuedAt()
.setIssuer(process.env.JWT_ISSUER) // issuer
.setAudience(process.env.JWT_AUDIENCE) // audience
.setExpirationTime(process.env.JWT_EXPIRATION_TIME) // token expiration time, e.g., "1 day"
.sign(secretKey); // secretKey generated from previous step
console.log(token); // log token to console
})();
验证 JWT
我们也将使用存储在 secretKey
中的相同对称密钥进行验证。以下代码可用于从请求 header 中提取令牌(在 Express 应用程序中)并验证令牌:
(async () => {
// extract token from request
const token = req.header('Authorization').replace('Bearer ', '');
try {
// verify token
const { payload, protectedHeader } = await jwtVerify(token, secretKey, {
issuer: process.env.JWT_ISSUER, // issuer
audience: process.env.JWT_AUDIENCE, // audience
});
// log values to console
console.log(payload);
console.log(protectedHeader);
} catch (e) {
// token verification failed
console.log("Token is invalid");
}
})();
到目前为止,生成密钥 material 的最简单方法是使用 generateKeyPair. The method is runtime agnostic and only requires a single argument - the Algorithm Identifier you wish to use the target key pair with. If you're bringing your own keys tho you must be aware of the different requirements 作为密钥,以便算法可以使用。
并非每个运行时的加密功能都可以支持所有算法,每个运行时的可用算法列表可用 here。
此外 - 导入 SPKI/PKCS8 编码密钥 material 是特定于平台的,并通过特定于平台的 API 完成。人们可以以 KeyLike
(CryptoKey(网络)、KeyObject(节点)或 Uint8Array(对称秘密)的类型别名)结束的方式记录在 KeyLike alias documentation
从使用的每个函数文档链接它。
如果您要为您的步骤提供任何实际的复制代码,我很乐意提供帮助。
The ‘sign’ method reports that the key must be a ‘KeyLike’, ‘CryptoKey’, or ‘Uint8Array’ type.
我很确定它在运行时说 KeyObject
,KeyLike 只是一个类型别名,涵盖适用于不同算法和运行时的所有不同类型的输入。
我很难理解如何使用 npm jose 模块 (https://www.npmjs.com/package/jose) 在我的 Node 应用程序中创建和验证签名的 JWT 令牌。我的场景是这样的:我想签署一个经过身份验证的请求来访问资源。我可以为此请求授予令牌成功创建 JWT 声明,该声明尊重“its”和“aud”、“exp”等属性,但我想对其进行签名(也就是说,使用 SignJWT 对象和“sign”方法),以便当它作为请求传回我的服务器时,我可以验证它并授予或拒绝访问权限。 “sign”方法似乎不喜欢我为“key”参数传递的任何东西(我没有传递任何选项——也许我应该传递,但是什么?)。 我正在尝试使用 RSA 密钥对。我想用私钥签名并用 public 密钥验证。对于我的迫切需要,我想我可以改用对称密钥,但我正在考虑其他一些未来的场景,在这些场景中我将需要证书密钥的这种经典 PKCS 关系。无论如何,我不认为这个选择与当前阻碍我进步的障碍有任何关系。 我首先尝试使用 jose/util/generate_key_pair 来创建我的 public/private 对。但是当我去使用密钥时,错误告诉我这不被我的实现支持。所以我转而尝试在我的应用程序之外创建一个“pem”证书并应用它(作为文本),但也失败了。 “sign”方法报告密钥必须是“KeyLike”、“CryptoKey”或“Uint8Array”类型。好吧,UInt8Array(节点缓冲区)没有足够的类型信息:它没有说明缓冲区中的内容,而“KeyLike”是一个模糊的定义,可以忽略。在求助于搜索引擎的神谕之后,我发现我可以使用以下来自 Node API 的 CryptoKey 格式创建密钥对:
crypto.webcrypto.subtle.generateKey(
{
name: 'RSASSA-PKCS1-v1_5',
modulusLength: 2048,
publicExponent: new Uint8Array([1, 0, 1]),
hash: "SHA-256"
},
true,
[‘sign’, ‘verify’]
).then((pair:any) => {
serverInstance.keyPair = pair
})
但是,当我到达签名部分时:
siaToken.sign(serverInstance.keyPair.privateKey).then(signature => {
我收到异常报告 “TypeError:CryptoKey 不支持此操作”
考虑到这可能与 generateKey 的“usages”参数有关,我在那里尝试了各种值,但没有成功。
所以,我很困惑。谁能告诉我如何 (a) 为此目的最好地生成一对密钥以及 (b) 如何将这些密钥应用于 JWT 签名?
我也一直在努力使用 jose
对 JWT 进行签名和验证,但最终能够成功使用 HS256 对称密钥加密。我通过以下步骤制作了它(我使用 jose-node-cjs-runtime
仅用于 Node.js 用例。请随意替换为所需的包。另请注意,我发现这些代码适用于 Node.js 版本 16.7.0, 16.9.0 所以请确保安装了它们中的任何一个。如果你想将这些更改部署到生产环境,那么你还必须确保部署环境具有相同的 Node.js 版本。一个实现这一点的方法是在 package.json
中的 engines
键中提及 Node.js 版本):
添加必需的导入
// library for generating symmetric key for jwt
const { createSecretKey } = require('crypto');
// library for signing jwt
const { SignJWT } = require('jose-node-cjs-runtime/jwt/sign');
// library for verifying jwt
const { jwtVerify } = require('jose-node-cjs-runtime/jwt/verify');
创建 KeyObject
类型的密钥
KeyObject
被 Node.js 推荐用于生成对称、非对称密钥时使用。使用以下代码生成 KeyObject
类型的对称密钥 object 并将其存储在 secretKey
.
const secretKey = createSecretKey(process.env.JWT_SECRET, 'utf-8');
用足够长的字符串替换process.env.JWT_SECRET
。它需要足够长(使用长度至少为 32 的字符串)否则在签署 JWT 时会抛出以下错误:HS256 requires symmetric keys to be 256 bits or larger
签署 JWT
(async () => {
const token = await new SignJWT({ id: '12345' }) // details to encode in the token
.setProtectedHeader({ alg: 'HS256' }) // algorithm
.setIssuedAt()
.setIssuer(process.env.JWT_ISSUER) // issuer
.setAudience(process.env.JWT_AUDIENCE) // audience
.setExpirationTime(process.env.JWT_EXPIRATION_TIME) // token expiration time, e.g., "1 day"
.sign(secretKey); // secretKey generated from previous step
console.log(token); // log token to console
})();
验证 JWT
我们也将使用存储在 secretKey
中的相同对称密钥进行验证。以下代码可用于从请求 header 中提取令牌(在 Express 应用程序中)并验证令牌:
(async () => {
// extract token from request
const token = req.header('Authorization').replace('Bearer ', '');
try {
// verify token
const { payload, protectedHeader } = await jwtVerify(token, secretKey, {
issuer: process.env.JWT_ISSUER, // issuer
audience: process.env.JWT_AUDIENCE, // audience
});
// log values to console
console.log(payload);
console.log(protectedHeader);
} catch (e) {
// token verification failed
console.log("Token is invalid");
}
})();
到目前为止,生成密钥 material 的最简单方法是使用 generateKeyPair. The method is runtime agnostic and only requires a single argument - the Algorithm Identifier you wish to use the target key pair with. If you're bringing your own keys tho you must be aware of the different requirements 作为密钥,以便算法可以使用。
并非每个运行时的加密功能都可以支持所有算法,每个运行时的可用算法列表可用 here。
此外 - 导入 SPKI/PKCS8 编码密钥 material 是特定于平台的,并通过特定于平台的 API 完成。人们可以以 KeyLike
(CryptoKey(网络)、KeyObject(节点)或 Uint8Array(对称秘密)的类型别名)结束的方式记录在 KeyLike alias documentation
从使用的每个函数文档链接它。
如果您要为您的步骤提供任何实际的复制代码,我很乐意提供帮助。
The ‘sign’ method reports that the key must be a ‘KeyLike’, ‘CryptoKey’, or ‘Uint8Array’ type.
我很确定它在运行时说 KeyObject
,KeyLike 只是一个类型别名,涵盖适用于不同算法和运行时的所有不同类型的输入。