如何使用QuickNode实现JSON WebToken(JWT)授权

  • QuickNode
  • 发布于 2024-06-22 22:52
  • 阅读 17

本文介绍了如何在区块链节点中集成JSON Web Tokens (JWT)以保护网络资源。文章详细讲解了JWT的核心概念,并通过一个React应用示例展示了如何生成、验证JWT,并将其用于请求和展示区块链数据。

概述

安全性是保护网络资源时的关键因素。保护这些资源的一种方式是将 JSON Web Tokens (JWT) 集成到你的 web 应用程序中。JWT 是一种开放标准,定义了一种在各方之间安全传输信息的简便方法。在本指南中,你将学习 JWT 的核心概念,以及如何在你的区块链节点上通过 QuickNode 启用 JWT。我们将通过创建一个 React 应用来演示这个过程,该应用将从我们的后端服务器(Express.js)获取 JWT,然后使用它来请求和显示前端的区块链数据。

你将需要什么

  • 一个由 QuickNode 提供支持的以太坊端点(在这里 创建一个免费账户)
  • 安装 Node.js
  • 一个终端窗口
  • (可选)基本的 React 和 Express.js 知识,以创建前端和后端应用程序

你将要做什么

  • 了解 JSON Web Tokens (JWT)
  • 创建一个简单的 Node.js 脚本来生成和验证 JWT
  • 使用 cURL 测试 JWT 验证
  • 使用 Express.js 创建一个 API 来提供 JWT Token
  • 使用 JWT 认证构建一个前端 React 应用
依赖 版本
node.js ^18.16.0
express ^4.19.2
jsonwebtoken ^9.0.2
react ^18.3.1

什么是 JWT?

JSON Web Tokens (JWT) 的思想,也称为 JOT,是创建一种标准和安全的方式,使两个主体能够进行通信。JWT 用于无状态会话管理(没有会话 cookie),后端服务器无需与授权服务器通信,因此可以带来好处。JWT 可以通过 URL、POST 参数或 HTTP 头部内部发送。由于 JWT 的大小,它们也是高效的。JWT 由三个部分组成:头部(Header)、有效载荷(Payload)和签名(Signature)。每部分由句点(".")分隔,并且源于 JSON 对象,然后通过 BASE64 编码为文本字符串。所有组件组合在一起表示如下格式:

header.payload.signature

RFC-7519 对该标准的定义有更多详细信息。要深入了解每个组件及其如何解码 JWT,请访问 JWT.io

这些组合的组件构成了一个 JWT。JWT 的示例可能看起来像这样:

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2Njk0Mzg4MDAsImlhdCI6MTY0ODgzNjY3Mn0.N4aNN5cwnYcMeZHeElrYtWcLxjfR-PqqLAvZNdCTGa-5wD_O3yFIM3F4ACX7egGXMCdob7UQwytMcMoAtnpKs8wyzdOlJgWyJIg3NsIWYdjnzuLz_EqNvIPdm3TEi7m0mZbgXLOGRQ_JS1RAF2i3XKPmhQuXq_ObSryPFfsLITimXJyoi5fiyX7WkUwJELIQVAlW5M5Um1fqIK791g52lIfM9vTU_PKIEJaMaBfUJMx92M04Mt8kYBjj7Eh1rxbEWeFA545HF_QKJe3j4EKoAx6BhL6oPCmoPoZXIAYlgAX6kf-FcbFfJ76u1ppeWsC0z_tfM5eDpVxHr2GY9d0o-A

kid(密钥 ID)

在 JWT 中,“kid”(密钥 ID)头部参数标识应该用来验证 JWT 签名的密钥。这个可选的区分大小写的字符串值(例如“0123456789”)对我们来说很有用,因为我们可能在一个区块链节点端点下有多个 JWT,并允许验证者知道在有多个密钥可用时应该使用哪个公钥。有关该参数的更多信息可以在 这里 找到。

使用 QuickNode 的 JWT

用户现在可以使用 JWT 认证方法来保护他们的区块链节点。QuickNode 支持单独的 JWT 或与我们的其他安全方法(如授权Token、推荐白名单和域名遮罩)集成。然而,请注意,如果在一个区块链节点上启用了多个身份验证服务,必须通过所有安全检查,或者用户请求将返回错误。

QuickNode 支持使用 RS256ECDSA256 算法创建的密钥对生成的 JWT,并且可以在一个区块链节点上同时激活的 JWT 数量没有限制(你只需确保使用适当的密钥 ID)。现在,我们准备创建我们的 React 应用程序了!

基本 JWT 示例

让我们从一个简单的 JWT 认证示例开始,使用 Node.js 脚本和 cURL。这将帮助了解核心概念,然后再构建完整的 React web 应用程序。

首先,创建一个新目录并初始化它:

mkdir quicknode-jwt-demo
cd quicknode-jwt-demo
npm init -y
npm install jsonwebtoken

接下来,让我们创建密钥对。

生成密钥对

在你的项目文件夹中创建一个名为 generateKeys.js 的文件,并输入以下代码(你可以根据需求使用 RSA256ES256 版本):

  • RSA256 JavaScript
  • ES256 JavaScript
// 导入的依赖
const fs = require('fs')
const { generateKeyPairSync } = require('crypto');
var jwt = require('jsonwebtoken');

// 生成 RSA 密钥
const { publicKey, privateKey } = generateKeyPairSync('rsa', {
    modulusLength: 2048,
    publicKeyEncoding: {
        type: 'spki',
        format: 'pem'
    },
    privateKeyEncoding: {
        type: 'pkcs8',
        format: 'pem',
    }
});

// 将密钥对写入文件
fs.writeFileSync('private_key.pem', privateKey);
console.log('已保存 private_key.pem');

fs.writeFileSync('public_key.pem', publicKey);
console.log('已保存 public_key.pem');
// 导入的依赖
const fs = require('fs')
const { generateKeyPairSync } = require('crypto');
var jwt = require('jsonwebtoken');

// 生成 ES256 密钥
const { publicKey, privateKey } = generateKeyPairSync('ec', {
    namedCurve: 'P-256',
    publicKeyEncoding: {
        type: 'spki',
        format: 'pem'
    },
    privateKeyEncoding: {
        type: 'pkcs8',
        format: 'pem',
    }
});

// 将密钥对写入文件
fs.writeFileSync('private_key.pem', privateKey);
console.log('已保存 private_key.pem');

fs.writeFileSync('public_key.pem', publicKey);
console.log('已保存 public_key.pem');

使用以下命令运行脚本:

node generateKeys.js

这将根据你的配置(例如,algorithm2048 位密钥长度(标准安全长度)spki/pem 格式)创建一个密钥对,生成以下文件:

  • private_key.pem:请妥善保存此文件,绝不要分享
  • public_key.pem:你将把它添加到你的 QuickNode 仪表板上

将公钥添加到 QuickNode 节点端点

首先,为 Ethereum Mainnet 创建一个 QuickNode 端点。然后,导航到你节点的 Security 标签,点击 禁用 JWTs 切换以启用设置,然后点击 添加 JWT 按钮。

JWT 部分 - QuickNode 端点

为你的 JWT 输入一个名称,并将先前在 public_key.pem 文件中生成的公钥粘贴到第二个字段中,标题为“公钥”。

JWT 部分 - QuickNode 端点

请注意公钥的格式应与上面的图像匹配。

添加后,公钥的 名称ID指纹 将显示在 JSON Web Token 部分。重要ID 字段中的值应与你的脚本(即 index.js)中的 keyid 值匹配,否则你将遇到未授权错误。

JWT 添加到节点安全性

接下来,我们将基于刚才创建的密钥对生成一个 JWT 。

生成 JWT

创建另一个名为 generateJWT.js 的文件,并输入以下代码:

// generateToken.js
const jwt = require('jsonwebtoken');
const fs = require('fs');

const privateKey = fs.readFileSync('private_key.pem');

// 生成一个Token
const token = jwt.sign({}, privateKey, {
  algorithm: 'RS256',
  expiresIn: '2d',
  keyid: '0123456789' // 你的任意 JWT ID
});

console.log(token);

运行该脚本以获取Token:

node generateJWT.js > token.txt

测试 JWT

现在使用 curl 测试Token:

TOKEN=$(cat token.txt)
curl -X POST \
  YOUR_QUICKNODE_HTTP_ENDPOINT \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'

请记得将 YOUR_QUICKNODE_HTTP_ENDPOINT 替换为你实际的 QuickNode 端点

如果成功,你将看到最新区块编号以十六进制值返回。这确认你 JWT 的设置正确无误。

就是这样!你刚刚学习了如何创建密钥对、生成 JWT 并使用 cURL 验证 JWT 是否有效。在下一部分,我们将展示一个类似的过程,而是构建一个使用 Express.js 的 React 应用和后端服务器。

使用 JWT 构建 React 应用

我们的应用将使用 Express.js 作为后端,这将创建一个 REST API,该 API 将通过特定端点提供 JWT Token。我们的 React 前端将获取此 JWT,然后使用它向区块链节点请求数据。以下步骤将向你展示如何在终端窗口中创建所需的文件,但请随便使用诸如 VScode 之类的代码编辑器。

在你希望创建项目的目录中打开一个终端窗口并运行以下命令:

npx create-react-app jwt-app && cd jwt-app

一旦我们的 React 应用初始化完成,让我们安装 JWT 实现所需的依赖项:

npm i express jsonwebtoken

然后我们将创建所需的文件,一个用于我们的 Express.js 后端服务器,另一个用于我们的密钥对生成。

touch index.js && touch generateKeys.js

我们还需要配置 package.json 文件以包含代理字段。代理字段将允许在我们的 React 应用和运行在 Express.js 上的后端服务器之间进行网关连接。在你的 package.json 文件中添加以下字段:

"proxy": "http://localhost:3001"

创建 JWT Token

接下来,在终端窗口中运行命令 nano generateKeys.js 以打开该文件(或使用像 VSCode 这样的代码编辑器)。然后在下面包含以下代码片段(例如,RSA256 JavaScript 或 ES256 JavaScript 示例):

  • RSA256 JavaScript
  • ES256 JavaScript
// 导入的依赖
const fs = require('fs')
const { generateKeyPairSync } = require('crypto');
var jwt = require('jsonwebtoken');

// 生成 RSA 密钥
const { publicKey, privateKey } = generateKeyPairSync('rsa', {
    modulusLength: 2048,
    publicKeyEncoding: {
        type: 'spki',
        format: 'pem'
    },
    privateKeyEncoding: {
        type: 'pkcs8',
        format: 'pem',
    }
});

// 将密钥对写入文件
fs.writeFileSync('private_key.pem', privateKey);
console.log('已保存 private_key.pem');

fs.writeFileSync('public_key.pem', publicKey);
console.log('已保存 public_key.pem');
// 导入的依赖
const fs = require('fs')
const { generateKeyPairSync } = require('crypto');
var jwt = require('jsonwebtoken');

// 生成 ES256 密钥
const { publicKey, privateKey } = generateKeyPairSync('ec', {
    namedCurve: 'P-256',
    publicKeyEncoding: {
        type: 'spki',
        format: 'pem'
    },
    privateKeyEncoding: {
        type: 'pkcs8',
        format: 'pem',
    }
});

// 将密钥对写入文件
fs.writeFileSync('private_key.pem', privateKey);
console.log('已保存 private_key.pem');

fs.writeFileSync('public_key.pem', publicKey);
console.log('已保存 public_key.pem');

按下 CTRL + X,然后在键盘上点击 Enter 以保存文件。保存完文件后,我们将运行命令 node generateKeys.js 以创建密钥对(public_key.pem 和 private_key.pem)并将其存储在同一目录中。请注意,该文件应仅运行一次,否则每次执行该文件时都会生成新的密钥对。

接下来的步骤是创建我们的服务器代码。运行命令 nano index.js 并输入以下代码:

// 导入库
const express = require("express");
const fs = require("fs");
const jwt = require("jsonwebtoken");

// 服务器代码
const PORT = process.env.PORT || 3001;
const app = express();

// 内存存储Token
let currentToken = null;
let tokenExpiration = null;

app.get('/get_token', (req, res) => { // 用于获取 JWT 的端点
  try {
    // 检查当前Token是否仍然有效
    if (currentToken) {
      try {
        const privateKey = fs.readFileSync(__dirname + "/private_key.pem");
        jwt.verify(currentToken, privateKey);
        if (tokenExpiration > Date.now()) {
          console.log("使用现有的Token,过期时间为:", (tokenExpiration - Date.now()) / 1000, "秒");
          return res.json({ token: currentToken }); // 返回现有有效的Token
        }
      } catch (err) {
        console.log("Token过期或无效,生成新Token");
        currentToken = null;
      }
    }

    // Token过期或不存在,创建一个新的
    const privateKey = fs.readFileSync(__dirname + "/private_key.pem");
    currentToken = jwt.sign({}, privateKey, {
      algorithm: 'RS256', // 用于创建 JWT 的算法,如有必要请更改为 ES256
      expiresIn: "2d", // 设置过期为 2 天
      keyid: '12345' // JSON Web Token 部分的 ID
    });

    // 设置过期时间
    tokenExpiration = Date.now() + (2 * 24 * 60 * 60 * 1000); // 2 天的毫秒值
    console.log("生成新的Token,过期时间为 2 天");
    return res.json({ token: currentToken }); // 返回新创建的 JWT
  } catch (error) {
    console.error('Token生成错误:', error);
    return res.status(500).json({ error: '生成Token失败' });
  }
});

app.listen(PORT, () => {
  console.log(`服务器在 ${PORT} 上监听`); // 在指定端口监听
});

警告

如果你之前使用 ES256 生成了公钥和私钥(而不是 RS256),请在 algorithm 字段中将上述值更改为 ES256

请记得保存该文件!现在,我们开始创建前端代码。

创建 React 前端

打开位于 src 目录中的 App.js 文件,并输入以下代码。还要记得将字符串 - "YOUR_QUICKNODE_HTTP ENDPOINT" 替换为你实际的 QuickNode 端点。如果你还没有端点,可以在这里 注册一个免费 QuickNode 账户并轻松设置端点!

import React from "react";
import "./App.css";

function App() {
  const [data, setData] = React.useState(null);

  React.useEffect(() => {
    fetch("/get_token")
      .then((res) => res.json())
      .then((token) => {

        fetch("YOUR_QUICKNODE_HTTP_ENDPOINT", { // 还没有?去 quicknode.com 现在就创建一个吧!
          method: 'POST',
          headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/json',
            'Authorization': `Bearer ${token.token}`
          },
          body: JSON.stringify({ method: "eth_blockNumber", params: [], id: 1, jsonrpc: "2.0" })
        }).then(res => res.json()).then(content => {
          console.log(content)
          setData(parseInt(content.result))
        });
      });
  })

  return (
    <div className="App">
      <header className="App-header">
        <p>{!data ? "加载中..." : data}</p>
      </header>
    </div>
  );
}

export default App;

我们快完成了!在我们可以启动应用程序之前,我们需要将我们的公钥对添加到我们的区块链节点。接下来让我们在 QuickNode 上设置 JWT 认证。

将公钥添加到 QuickNode 节点端点

首先,为 Ethereum Mainnet 创建一个 QuickNode 端点。然后,导航到你节点的 Security 标签,点击 禁用 JWTs 切换以启用设置,然后点击 添加 JWT 按钮。

JWT 部分 - QuickNode 端点

为你的 JWT 输入一个名称,并将先前在 public_key.pem 文件中生成的公钥粘贴到第二个字段中,标题为“公钥”。

JWT 部分 - QuickNode 端点

请注意公钥的格式应与上面的图像匹配。

添加后,公钥的 名称ID指纹 将显示在 JSON Web Token 部分。重要ID 字段中的值应与你的脚本(即 index.js)中的 keyid 值匹配,否则你将遇到未授权错误。

JWT 添加到节点安全性

启动 React 应用

在启动 Express API 和 React 应用之前,让我们总结一下它们将如何协作。

  1. Express.js API 将提供我们的 /get_token 端点,该端点一旦被调用,将读取本地私钥,创建并签署 JWT 有效载荷,然后返回签名的 JWT。
  2. React 应用将调用 /get_token 端点并获取签名的 JWT(即 bearer Token)。
  3. 然后,React 应用将对 QuickNode 端点发起调用以使用 eth_blockNumber RPC 方法获取最新区块号,并将签名的 JWT 包含在请求头中。
  4. 如果调用成功且 JWT 被授权,则 React 应用将返回最新区块号

现在,我们需要打开两个终端窗口,以便可以同时运行后端服务器和 React 应用。

要启动后端服务器,在一个终端窗口中运行命令 node index.js。如果服务器正在运行,你应该会看到以下输出:“服务器在 3001 上监听”

然后,在另一个终端窗口中运行命令 npm start 启动 React 应用。浏览器窗口应该会自动打开到应用运行的端口,你应该会看到类似以下的结果:

React 应用程序显示最新区块号

如果你想进一步深入了解,请查看这个精彩的 GitHub 存储库,它展示了如何在 QuickNode 上实现与 JWT 认证的 Cloudflare workers。

下面是一些用户在使用 QuickNode 的 JWT 时可能会有的常见问题的答案。如果你对该功能或其他功能有任何进一步的问题,请随时与我们联系!

你可能会有的问题

问:支持在哪些链上使用 JWT?

答: JWT 在所有链上均受支持。

问: 在过期前,我如何丢弃 JWT?

答: 如果你的 JWT 可能已暴露,并且你希望阻止其被使用,你可以从节点的安全选项卡中移除公钥。

问: 我可以将多个 JWT 添加到一个区块链节点吗?

答: 在一个区块链节点上同时激活的 JWT 数量没有限制。如果多个 JWT 正在激活,则确保在 keyid 字段中使用适当的 ID 值,对应于你在签署 JWT 时使用的公钥/私钥。有关更多信息,请参见 这里

问: QuickNode 支持哪种加密方式?

答: 目前只支持 RSA 256 (RS256) 和 ECDSA 256 (ES256),如 RFC7518 表 3.1 中所述。

问: 如何解决 401 错误?

答: 你可能已经在你的区块链节点上启用了其他形式的安全方法。请检查以确保你的请求满足所有安全检查。

问: 我应该选择什么过期日期?

答: 你可以设置所希望的任何将来的过期日期。通常,过期时间越短,JWT 的安全性越高。

结论

恭喜你完成本指南!我们学习了 JWT 及如何通过 QuickNode 在你的区块链节点上启用它。请订阅我们的 通讯,以获取更多关于以太坊的文章和指南。如果你有任何反馈,请随时通过 Twitter 与我们联系。你也可以在我们的 Discord 社区服务器上与我们聊天,那里聚集了一些你可能遇到的最酷的开发人员 😃

我们 ❤️ 反馈!

让我们知道 如果你有任何反馈或对新主题的请求。我们很乐意听到你的声音。

  • 原文链接: quicknode.com/guides/qui...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
QuickNode
QuickNode
江湖只有他的大名,没有他的介绍。