生成 JWT 表单头和有效负载

Posted

技术标签:

【中文标题】生成 JWT 表单头和有效负载【英文标题】:Generate JWT form header and payload 【发布时间】:2020-08-26 03:21:11 【问题描述】:

我正在使用 node js 在我的后端服务器中创建一个 jwt。 我正在使用库来签名/验证 JWT,它工作正常。一旦一个 jwt.io 我粘贴了我登录时获得的令牌,我就可以在有效负载中看到我的数据。 所以问题是我正在尝试从标头和我在 jwt.io 中返回的有效负载生成签名 这是我试图做的,但它不起作用,我有点困惑。 用于签名的算法是默认的HS256。

const crypto = require("crypto");

// encode base64 the header
let jsonHeader = JSON.stringify(
  alg: "HS256",
  typ: "JWT",
);
let bs64header = Buffer.from(jsonHeader).toString("base64").split("=")[0];
console.log("bs64header :>>\n ", bs64header); //look the same as the token i got

// encode vase64 the payload
let jsonPayload = JSON.stringify(
  id: "5eb20004ac94962628c68b91",
  iat: 1589125343,
  exp: 1589989343,
  jti: "37743739b1476caa18ca899c7bc934e1aba63ba1",
);
let bs64payload = Buffer.from(jsonPayload).toString("base64").split("=")[0];
console.log("bs64Payload :>> \n", bs64payload); //look the same as the token i got

// TRY to generate the signature from the Base64Header and Base64Payload
// with the secret code that i used to sign the JWT
let secret = "0d528cb666023eee0d44e725fe9dfb751263d2f68f07998ae7388ff43b1b504f";
let signature = bs64header + "." + bs64payload;

let hashed = crypto
  .createHash("sha256", secret)
  .update(signature)
  .digest("hex");

console.log("hashed :>> \n", hashed);

let bs64signature = Buffer.from(hashed).toString("base64").split("=")[0];
console.log("bs64signature>>", bs64signature); //This is where i got stuck.

// let jwt = bs64header + "." + bs64payload + "." + bs64signature;
// console.log("jwt>>", jwt);


【问题讨论】:

为什么要自己生成jwt字符串??我想您需要查看npmjs.com/package/jsonwebtoken。这将大大减少您的代码以及您为创建令牌所做的所有手动步骤。令牌非常敏感,结构上的一个错误,您将无法验证或读取它。 我使用 jwt.sign() 创建令牌并使用 jwt.verify() 检查令牌是否良好。但是当我想为用户创建一个注销根时,这两种方法并不安全。所以我需要在 Payload 中使用一些自定义声明创建自己的令牌,以便稍后进行一些验证! 您可以在通过 JSONWebToken 库创建令牌时添加自定义声明。这些方法不安全的事实到底是什么意思?你可以在你的令牌中提供一个角色范围来检查它是什么类型的用户。 其实我是我的错,没有对 JWT 做更多的研究并试图理解它。我也同意你的第一条评论,使用 npmjs.com/package/jsonwebtoken 也会更有用。但这是一个很好的练习,有助于更好地了解 JWT 的工作原理以及如何自己制作。 【参考方案1】:

我已经对您的代码进行了很多修改,以减少重复性并且更易于阅读。我不完全确定这是否会起作用,所以如果有任何错误,请发表评论。

我已经在runkit 中对其进行了测试,并且还检查了应该使用jwt.io 的输出。输出看起来是一样的,所以我很确定这是可行的。

变化

创建了一个函数来base64对对象和字符串进行编码。 创建了一个函数以使 base64 字符串使用 URL 安全字符集。 将crypto.createHash() 更改为crypto.createHmac(),以便实际使用密钥。
// base64 encode the data
function bs64encode(data) 
  if (typeof data === "object") 
    data = JSON.stringify(data);
  

  return bs64escape(Buffer.from(data).toString("base64"));


// modify the base64 string to be URL safe
function bs64escape(string) 
  return string.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");




// base64 encode the header
let bs64header = bs64encode(
  alg: "HS256",
  typ: "JWT"
);

console.log("bs64header :>>\n ", bs64header);


// base64 encode the payload
let bs64payload = bs64encode(
  id: "5eb20004ac94962628c68b91",
  iat: 1589125343,
  exp: 1589989343,
  jti: "37743739b1476caa18ca899c7bc934e1aba63ba1"
);

console.log("bs64payload :>> \n", bs64payload);


// generate the signature from the header and payload
let secret = "0d528cb666023eee0d44e725fe9dfb751263d2f68f07998ae7388ff43b1b504f";
let signature = bs64header + "." + bs64payload;

let bs64signature = bs64escape(crypto
  .createHmac("sha256", secret)
  .update(signature)
  .digest("base64"));

console.log("bs64signature>>", bs64signature);


let jwt = bs64header + "." + bs64payload + "." + bs64signature;

console.log("jwt>>", jwt);

【讨论】:

谢谢!!这工作也是。在检查您的答案之前,我也是一个解决方案。所以我缺少的是这个 - 创建了一个函数来使 base64 字符串使用 URL 安全字符集。 - 将 crypto.createHash() 更改为 crypto.createHmac(),以便实际使用密钥。

以上是关于生成 JWT 表单头和有效负载的主要内容,如果未能解决你的问题,请参考以下文章

JWT 有效负载中的令牌

在 java 中创建带有标头、有效负载和签名的 JWT

WSO2 APIM - 在 JWT 有效负载中添加用户角色

firebase如何发送一个有效负载包含下划线字符的JWT令牌?

Java - 从请求 JSON 生成 JWS/JWT

如何使用 JJWT 从有效负载中获取自定义字段