JWT开发详解

文章目录

一、JWT理论基础

JSON Web Token(JWT)是一种开放标准(RFC 7519),用于在网络上以紧凑且自包含的方式安全地传输信息。JWT 被设计为在用户和服务之间传递声明信息,以便进行身份验证和授权。该标准定义了一种简洁的、自包含的方法,可以传递使用 JSON 对象进行编码的信息,这些信息可以被验证和信任。

JWT 由三个部分组成:Header、Payload 和 Signature。这三部分通过.符号分隔,并以Base64编码的形式进行表示。

  1. Header(头部):

    • Header 包含了两部分信息,分别是 token 的类型(JWT)和使用的签名算法,例如:

      json 复制代码
      {
        "alg": "HS256",
        "typ": "JWT"
      }
    • 上述例子表示使用 HMAC SHA-256 算法进行签名。

  2. Payload(负载):

    • Payload 包含了声明(claims)。声明是关于实体(通常是用户)和其他数据的声明。有三种类型的声明:

      • 注册声明(Registered claims): 这些是一组预定义的声明,包括 iss(签发者)、sub(主题)、aud(受众)、exp(过期时间)、nbf(不可用之前的时间)和 iat(发布时间)。
      • 公共声明(Public claims): 可以根据需要定义的声明。
      • 私有声明(Private claims): 用于在同意使用它们的双方之间共享信息。
    • 例如:

      json 复制代码
      {
        "sub": "1234567890",
        "name": "John Doe",
        "admin": true
      }
  3. Signature(签名):

    • 使用编码的 header、编码的 payload 和一个秘密密钥来创建签名部分。签名用于验证消息在传递过程中是否被篡改。

    • 例如:

      复制代码
      HMACSHA256(
        base64UrlEncode(header) + "." +
        base64UrlEncode(payload),
        secret)

JWT 的工作流程通常如下:

  1. 用户进行身份验证,并且身份验证成功后,服务器会生成一个包含用户信息的 JWT,并将其返回给用户。
  2. 用户在之后的请求中将 JWT 放入请求的头部(通常是 Authorization 头部)中。
  3. 服务器在接收到请求时,使用之前共享的密钥来验证 JWT 的签名,以确保信息的完整性。
  4. 如果签名验证成功,服务器可以使用 JWT 中的信息进行授权判断。

优势和特点:

  • 简洁性: JWT 使用 JSON 数据格式,具有良好的可读性和编码/解码的便捷性。
  • 自包含: JWT 包含了所有需要的信息,避免了每次请求时都需要查询数据库的开销。
  • 可靠性: JWT 的签名机制保证了消息的完整性,防止了信息被篡改的可能性。
  • 跨域: 可以在不同的域之间进行信息传递,支持跨域应用场景。

需要注意的是,由于 JWT 使用了 Base64 编码,虽然可以在客户端解码查看,但不能修改,因为修改后签名验证将失败。然而,JWT 中的信息仍然是可见的,因此敏感信息应该被妥善处理。

二、JWT使用实例

2.1 服务端代码

编写一个完整的 JWT 项目涉及多个方面,包括用户认证、生成和验证 JWT、路由保护等。下面是一个简单的示例,使用 Node.js 和 Express 框架实现:

首先,确保你已经安装了 Node.js 和 npm。然后,创建一个新目录,执行以下步骤:

  1. 初始化项目:

    bash 复制代码
    npm init -y
  2. 安装依赖:

    bash 复制代码
    npm install express jsonwebtoken body-parser
  3. 创建一个 server.js 文件:

    javascript 复制代码
    const express = require('express');
    const jwt = require('jsonwebtoken');
    const bodyParser = require('body-parser');
    
    const app = express();
    const PORT = 3000;
    const SECRET_KEY = 'your_secret_key';
    
    app.use(bodyParser.json());
    
    // 用户数据库(示例)
    const users = [
      { id: 1, username: 'user1', password: 'password1' },
      { id: 2, username: 'user2', password: 'password2' },
    ];
    
    // 登录路由
    app.post('/login', (req, res) => {
      const { username, password } = req.body;
    
      // 实际项目中应该通过数据库查询验证用户信息
      const user = users.find((u) => u.username === username && u.password === password);
    
      if (user) {
        // 生成 JWT
        const token = jwt.sign({ userId: user.id, username: user.username }, SECRET_KEY, { expiresIn: '1h' });
        res.json({ token });
      } else {
        res.status(401).json({ error: 'Invalid credentials' });
      }
    });
    
    // 保护路由
    app.get('/protected', (req, res) => {
      const token = req.header('Authorization');
    
      if (!token) {
        return res.status(401).json({ error: 'Unauthorized' });
      }
    
      // 验证 JWT
      jwt.verify(token, SECRET_KEY, (err, decoded) => {
        if (err) {
          return res.status(401).json({ error: 'Invalid token' });
        }
    
        res.json({ message: 'You are authorized!', user: decoded });
      });
    });
    
    app.listen(PORT, () => {
      console.log(`Server is running on http://localhost:${PORT}`);
    });
  4. 运行应用:

    bash 复制代码
    node server.js

现在,你的应用将在 http://localhost:3000 上运行。你可以使用 Postman 或其他工具模拟登录请求,然后将生成的 token 用于访问 /protected 路由。

请注意,以上示例是一个简单的演示,实际项目中需要更复杂的用户认证和安全性措施。在生产环境中,你可能需要使用 HTTPS、存储更安全的密钥、使用数据库进行用户验证等。

2.2 客户端代码

客户端部分通常是一个前端应用,可以使用 HTML、CSS、JavaScript(通常使用框架如 React、Vue.js 或 Angular)来实现。在客户端,主要任务包括用户界面的设计、用户登录、JWT 的处理、以及向服务器发起请求等。

以下是一个简单的 HTML、CSS、JavaScript 示例,使用原生 JavaScript 实现:

  1. 创建一个 index.html 文件:
html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>JWT Demo - Client</title>
</head>
<body>
  <h1>JWT Demo - Client</h1>
  <div id="login-form">
    <label for="username">Username:</label>
    <input type="text" id="username" required>
    <br>
    <label for="password">Password:</label>
    <input type="password" id="password" required>
    <br>
    <button onclick="login()">Login</button>
  </div>
  <div id="protected-content" style="display: none;">
    <h2>Protected Content</h2>
    <p id="message"></p>
  </div>

  <script>
    function login() {
      const username = document.getElementById('username').value;
      const password = document.getElementById('password').value;

      fetch('http://localhost:3000/login', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({ username, password }),
      })
      .then(response => response.json())
      .then(data => {
        if (data.token) {
          // 登录成功,显示保护内容
          document.getElementById('login-form').style.display = 'none';
          document.getElementById('protected-content').style.display = 'block';
          document.getElementById('message').innerText = 'Loading...';

          // 使用获取的 token 访问受保护的路由
          fetch('http://localhost:3000/protected', {
            headers: {
              'Authorization': data.token,
            },
          })
          .then(response => response.json())
          .then(protectedData => {
            document.getElementById('message').innerText = `Welcome, ${protectedData.user.username}!`;
          })
          .catch(error => console.error('Error fetching protected content:', error));
        } else {
          alert('Invalid credentials');
        }
      })
      .catch(error => console.error('Login error:', error));
    }
  </script>
</body>
</html>

这个简单的 HTML 文件包含一个登录表单和一个显示受保护内容的部分。当用户成功登录后,它会获取 JWT,并使用该令牌向服务器发起受保护路由的请求。

请注意,这只是一个基础示例,实际项目中应该考虑更多的安全性和用户体验问题。前端应用通常会使用一些框架,以更好地组织和管理代码。

三、JWT流程

以下是一个使用 Mermaid 语法绘制的简单 JWT 流程图:

  1. 提供用户名和密码 2. 验证用户信息 3. 发送JWT 4. 包含JWT的请求 5. 验证JWT 6. 返回受保护资源 用户 服务器 生成JWT 服务器 授权访问

这个流程图简要描述了 JWT 的使用过程:

  1. 用户提供用户名和密码。
  2. 服务器验证用户信息。
  3. 如果验证成功,服务器生成 JWT。
  4. 服务器将包含 JWT 的响应发送给用户。
  5. 用户在后续请求中包含 JWT。
  6. 服务器验证 JWT 并授权用户访问受保护资源。

请注意,这只是一个高层次的概述,实际流程可能因应用场景而异,例如,在生成 JWT 时可能涉及更多的步骤,而在验证 JWT 时可能涉及更多的安全性检查。

相关推荐
gnip1 小时前
企业级配置式表单组件封装
前端·javascript·vue.js
一只叫煤球的猫2 小时前
写代码很6,面试秒变菜鸟?不卖课,面试官视角走心探讨
前端·后端·面试
excel3 小时前
Three.js 材质(Material)详解 —— 区别、原理、场景与示例
前端
掘金安东尼3 小时前
抛弃自定义模态框:原生Dialog的实力
前端·javascript·github
hj5914_前端新手7 小时前
javascript基础- 函数中 this 指向、call、apply、bind
前端·javascript
薛定谔的算法7 小时前
低代码编辑器项目设计与实现:以JSON为核心的数据驱动架构
前端·react.js·前端框架
Hilaku7 小时前
都2025年了,我们还有必要为了兼容性,去写那么多polyfill吗?
前端·javascript·css
yangcode7 小时前
iOS 苹果内购 Storekit 2
前端
LuckySusu7 小时前
【js篇】JavaScript 原型修改 vs 重写:深入理解 constructor的指向问题
前端·javascript
LuckySusu7 小时前
【js篇】如何准确获取对象自身的属性?hasOwnProperty深度解析
前端·javascript