我正在努力了解如何使用 npm jose 模块(https://www.npmjs.com/package/jose)在我的 Node 应用程序中创建和验证签名的 JWT 令牌。我的场景是这样的:我想签署经过身份验证的请求来访问资源。我可以成功为此请求授予令牌创建 JWT 声明,该声明尊重 \xe2\x80\x9cits\xe2\x80\x9d 和 \xe2\x80\x9caud\xe2\x80\x9d、\xe2\x80\x9cexp\ 的属性xe2\x80\x9d 等,但我想对其进行签名(即使用 SignJWT 对象和 \xe2\x80\x98sign\xe2\x80\x99 方法),以便当它作为请求我可以验证它并授予或拒绝访问。\n\n\xe2\x80\x9csign\xe2\x80\x9d 方法不\xe2\x80\x99t 似乎喜欢我为 \xe2\x80\x98key\xe2 传递的任何内容\x80\x99 参数(我没有传递任何选项 \xe2\x80\x94 也许我应该传递,但是什么?)。\n我正在尝试使用 RSA 密钥对。我想用私钥签名并用公钥验证。为了满足我的迫切需要,我想我可以使用对称密钥,但我正在考虑其他一些未来场景,在这些场景中我将需要证书密钥的这种经典 PKCS 关系。无论如何,我不\xe2\x80\x99认为这个选择与当前我的进步的障碍有任何关系。\n我首先尝试使用 jose/util/generate_key_pair 创建我的公共/私有对。但是当我去使用密钥时,错误告诉我我的实现不支持这一点。因此,我转而尝试在我的应用程序之外创建 \xe2\x80\x98pem\xe2\x80\x99 证书并应用它(作为文本),但这也失败了。\xe2\x80\x98sign\xe2\x80\x99 方法报告密钥必须是 \xe2\x80\x98KeyLike\xe2\x80\x99、\xe2\x80\x98CryptoKey\xe2\x80\x99 或 \xe2 \x80\x98Uint8Array\xe2\x80\x99 类型。好吧,UInt8Array(节点缓冲区)没有足够的类型信息:它不\xe2\x80\x99t说明该缓冲区中的内容,而\xe2\x80\x9cKeyLike\xe2\x80\x9d是一个如此模糊的定义,它\xe2\x80\x99s 可以忽略。在请求搜索引擎的神谕之后,我发现我可以使用 Node API 中的以下内容创建 CryptoKey 格式的密钥对:
\ncrypto.webcrypto.subtle.generateKey(\n {\n name: \'RSASSA-PKCS1-v1_5\',\n modulusLength: 2048,\n publicExponent: new Uint8Array([1, 0, 1]),\n hash: "SHA-256"\n },\n true,\n [\xe2\x80\x98sign\xe2\x80\x99, \xe2\x80\x98verify\xe2\x80\x99]\n).then((pair:any) => {\n serverInstance.keyPair = pair\n})\nRun Code Online (Sandbox Code Playgroud)\n但是,当我到达签名部分时:\nsiaToken.sign(serverInstance.keyPair.privateKey).then(signature => {
我收到一个异常,报告\n\xe2\x80\x9cTypeError: CryptoKey 不支持此操作\xe2\x80\x9d
\n认为这可能与generateKey的\xe2\x80\x98usages\xe2\x80\x99参数有关,我在那里尝试了各种值,但没有成功。
\n所以,我很困惑。谁能告诉我如何 (a) 最好地为此目的生成一对密钥以及 (b) 如何将这些密钥应用于 JWT 签名?
\n我也在使用 JWT 进行签名和验证方面遇到了困难,jose但最终能够通过 HS256 对称密钥加密取得成功。我通过以下步骤生成了它(我jose-node-cjs-runtime仅用于 Node.js 用例。请随意替换为所需的包。另请注意,我发现这些代码适用于 Node.js 版本 16.7.0、16.9.0所以请确保安装其中任何一个。如果要将这些更改部署到生产环境,那么还必须确保部署环境具有相同的 Node.js 版本。实现此目的的一种方法是提及 Node.jsengines键入 中的版本package.json:
// 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');
Run Code Online (Sandbox Code Playgroud)
KeyObjectKeyObjectNode.js 建议在生成对称、非对称密钥时使用。使用以下代码生成并存储KeyObject中类型的对称密钥对象secretKey。
const secretKey = createSecretKey(process.env.JWT_SECRET, 'utf-8');
Run Code Online (Sandbox Code Playgroud)
替换process.env.JWT_SECRET为足够长的字符串。它需要足够长(使用长度至少为 32 的字符串),否则在签署 JWT 时会抛出以下错误:HS256 要求对称密钥为 256 位或更大
(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
})();
Run Code Online (Sandbox Code Playgroud)
secretKey我们也将使用存储的相同对称密钥进行验证。以下代码可用于从请求标头(在 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");
}
})();
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
19970 次 |
| 最近记录: |