jwt在登录时进行token的加密

前端

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>JWT 鉴权机制</title>
    <link
      rel="stylesheet"
      href="node_modules/bootstrap/dist/css/bootstrap.min.css"
    />
  </head>
  <body>
    <div class="container clearfix">
      <form class="mt-5">
        <div class="mb-3">
          <label class="form-label">用户名</label>
          <input
            type="text"
            class="form-control"
            name="username"
            value="zhangsan"
          />
        </div>
        <div class="mb-3">
          <label class="form-label">密码</label>
          <input
            type="password"
            class="form-control"
            name="password"
            value="123456"
          />
        </div>
        <button type="submit" class="btn btn-primary">登录</button>
      </form>
      <button type="button" class="btn btn-secondary mt-5" id="protectedBtn">
        访问受保护的资源
      </button>
    </div>
    <script src="node_modules/axios/dist/axios.min.js"></script>
    <script>
      // 获取表单 DOM 对象
      const form = document.querySelector("form");
      // 获取受保护资源按钮 DOM 对象
      const protectedBtn = document.querySelector("#protectedBtn");

      // 监听表单的提交事件
      form.addEventListener("submit", async (e) => {
        // 阻止表单默认提交行为
        e.preventDefault();
        // 获取表单数据
        const formData = new FormData(form);
        const username = formData.get("username");
        const password = formData.get("password");

        try {
          // 发送 POST 请求到登录接口
          const response = await axios.post("http://localhost:3000/login", {
            username,
            password,
          });
          // 将 token 存储在 localStorage
          localStorage.setItem("accessToken", response.data.accessToken);
          localStorage.setItem("refreshToken", response.data.refreshToken);
          // 可以重定向到其他页面或显示登录成功信息
          alert("登录成功!");
        } catch (error) {
          // 处理错误,例如显示登录失败信息
          alert(error.response.data.message);
        }
      });

      // 监听按钮的点击事件
      protectedBtn.addEventListener("click", async () => {
        try {
          // 从 localStorage 获取 accessToken
          const accessToken = localStorage.getItem("accessToken");
          if (!accessToken) {
            alert("未登录或登录已过期,请重新登录获取访问令牌。");
            return;
          }

          // 发送 GET 请求到受保护的资源接口
          const response = await axios.get("http://localhost:3000/protected", {
            headers: {
              Authorization: `Bearer ${accessToken}`,
            },
          });

          // 显示受保护资源的数据
          alert(response.data.message);
        } catch (error) {
          if (error.response && error.response.status === 401) {
            // 如果访问令牌过期,尝试使用刷新令牌获取新的访问令牌
            try {
              const refreshToken = localStorage.getItem("refreshToken");
              const refreshResponse = await axios.post(
                "http://localhost:3000/refresh",
                {
                  refreshToken,
                }
              );
              localStorage.setItem(
                "accessToken",
                refreshResponse.data.accessToken
              );
              localStorage.setItem(
                "refreshToken",
                refreshResponse.data.refreshToken
              );

              // 重新尝试原来的请求
              const retryResponse = await axios.get(
                "http://localhost:3000/protected",
                {
                  headers: {
                    Authorization: `Bearer ${refreshResponse.data.accessToken}`,
                  },
                }
              );
              alert(retryResponse.data.message);
            } catch (refreshError) {
              alert("无法刷新令牌,请重新登录。");
            }
          } else {
            alert(error.response.data.message);
          }
        }
      });
    </script>
  </body>
</html>

后端

// 引入必要的模块
const express = require("express");
const bodyParser = require("body-parser");
const jwt = require("jsonwebtoken");
const bcrypt = require("bcryptjs");
const cors = require("cors");

// 创建 Express 应用
const app = express();
const PORT = 3000;

// 定义 JWT 密钥
const SECRET_KEY = "your_secret_key";
const REFRESH_SECRET_KEY = "your_refresh_secret_key";

// 允许跨域访问
app.use(cors());

// 使用 bodyParser 中间件来解析 JSON 请求体
app.use(bodyParser.json());

// 用户数据,通常应该存储在数据库中
const users = [
  {
    id: 1,
    username: "zhangsan",
    password: bcrypt.hashSync("123456", 10),
  },
];

// 登录接口
app.post("/login", async (req, res) => {
  const { username, password } = req.body;
  const user = users.find((u) => u.username === username);
  if (!user) {
    return res.status(401).json({ message: "登录失败1" });
  }
  const isPasswordValid = await bcrypt.compare(password, user.password);
  if (!isPasswordValid) {
    return res.status(401).json({ message: "登录失败2" });
  }
  const accessToken = jwt.sign({ id: user.id }, SECRET_KEY, {
    expiresIn: "15m",
  });
  const refreshToken = jwt.sign({ id: user.id }, REFRESH_SECRET_KEY, {
    expiresIn: "7d",
  });
  res.json({ accessToken, refreshToken });
});

// 刷新令牌接口
app.post("/refresh", (req, res) => {
  const { refreshToken } = req.body;
  try {
    const decoded = jwt.verify(refreshToken, REFRESH_SECRET_KEY);
    const newAccessToken = jwt.sign({ id: decoded.id }, SECRET_KEY, {
      expiresIn: "15m",
    });
    const newRefreshToken = jwt.sign({ id: decoded.id }, REFRESH_SECRET_KEY, {
      expiresIn: "7d",
    });
    res.json({ accessToken: newAccessToken, refreshToken: newRefreshToken });
  } catch (error) {
    return res.status(401).json({ message: "刷新令牌失败" });
  }
});

// JWT 验证中间件
function authenticateToken(req, res, next) {
  const authHeader = req.headers["authorization"];
  const token = authHeader && authHeader.split(" ")[1];
  if (token == null) return res.sendStatus(401);
  jwt.verify(token, SECRET_KEY, (err, user) => {
    if (err)
      return res.status(401).json({ message: "未能成功访问到受保护的资源" });
    req.user = user;
    next();
  });
}

// 受保护的资源接口
app.get("/protected", authenticateToken, (req, res) => {
  res.json({
    message: `欢迎, 你的 ID 是 ${req.user.id}. 你正在访问受保护的资源`,
  });
});

// 启动服务器
app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值