You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MVC架构后端JWT条件渲染实现及前端JWT解析用户ID问题

两个JWT相关问题的解决方案

问题1:MVC架构后端中用JWT实现条件渲染

条件渲染的核心是前端根据用户身份/权限展示不同内容,后端通过JWT验证用户身份并返回专属数据,配合前端逻辑完成渲染。结合你的现有代码,具体实现步骤如下:

1. 后端:用JWT保护需权限的路由

在mainRoutes.js中,将verifyToken中间件应用到需要用户身份的路由上(比如用户积分接口),确保只有携带有效JWT的请求才能访问:

// 修改user_points路由,添加JWT验证中间件
router.use("/user_points", jwtMiddleware.verifyToken, userPointsRoute);

此时后端会自动解码token,将用户ID存入res.locals.userId,后续控制器可直接使用该ID查询用户专属数据。

2. 后端控制器:返回用户专属积分数据

在userPointsController中,利用res.locals.userId查询当前登录用户的积分:

module.exports.getUserPoints = (req, res) => {
  const userId = res.locals.userId;
  // 数据库查询该用户的总积分
  db.query("SELECT total_points FROM user_points WHERE user_id = ?", [userId], (err, results) => {
    if (err) return res.status(500).json({ error: "积分查询失败" });
    res.status(200).json({ totalPoints: results[0].total_points });
  });
};

3. 前端:携带JWT请求数据并做条件渲染

从localStorage取出token,通过你已有的fetchMethod请求接口,拿到数据后根据用户信息渲染页面:

document.addEventListener("DOMContentLoaded", function () {
  const token = localStorage.getItem("token");
  if (token) {
    // 请求当前用户的积分数据
    fetchMethod(currentUrl + "/api/user_points", (status, data) => {
      if (status === 200) {
        // 渲染用户积分
        document.getElementById("userPoints").innerText = `总积分:${data.totalPoints}`;
        // 条件渲染示例:积分大于100时显示特权按钮
        if (data.totalPoints > 100) {
          document.getElementById("vipButton").classList.remove("d-none");
        }
      }
    }, "GET", null, token);
  } else {
    // 未登录状态:显示登录入口,隐藏用户专属内容
    document.getElementById("loginSection").classList.remove("d-none");
    document.getElementById("userSection").classList.add("d-none");
  }
});

问题2:前端从localStorage的JWT中获取user_id(无法访问Node.js模块)

你遇到的问题是浏览器环境(public目录)无法使用Node.js的jsonwebtoken模块,以下两种方案可以解决:

方案1:纯JS手动解码JWT(无需额外库)

JWT由header.payload.signature三部分组成,其中payload是Base64URL编码的JSON,可手动解码:

document.addEventListener("DOMContentLoaded", function () {
  const token = localStorage.getItem("token");
  if (token) {
    try {
      // 拆分token,提取payload部分
      const payloadBase64 = token.split(".")[1];
      // 转换Base64URL为标准Base64并解码
      const decodedPayload = JSON.parse(atob(payloadBase64.replace(/-/g, "+").replace(/_/g, "/")));
      const userId = decodedPayload.userId;
      console.log("用户ID:", userId);

      // 拿到ID后请求用户积分(仍需携带完整token做后端验证)
      fetchMethod(currentUrl + "/api/user_points", (status, data) => {
        if (status === 200) {
          document.getElementById("userPoints").innerText = `总积分:${data.totalPoints}`;
        }
      }, "GET", null, token);
    } catch (err) {
      console.error("Token解码失败:", err);
      // 解码失败说明token无效,清除存储并跳转登录页
      localStorage.removeItem("token");
      window.location.href = "login.html";
    }
  } else {
    console.error("未找到用户Token");
  }
});

⚠️ 注意:手动解码仅能获取payload内容,无法验证token的真实性,所有权限逻辑必须由后端的verifyToken中间件完成。

方案2:引入前端JWT解码库

使用轻量的前端解码库jwt-decode:

  1. 下载库的浏览器版本,放到public/js目录
  2. 在HTML中引入脚本:
<script src="/js/jwt-decode.min.js"></script>
  1. 使用库解码token:
document.addEventListener("DOMContentLoaded", function () {
  const token = localStorage.getItem("token");
  if (token) {
    try {
      const decodedToken = jwt_decode(token);
      const userId = decodedToken.userId;
      console.log("用户ID:", userId);

      // 后续请求逻辑...
    } catch (err) {
      console.error("Token解码失败:", err);
      localStorage.removeItem("token");
      window.location.href = "login.html";
    }
  }
});

补充提示

  • 前端不要依赖解码后的JWT做权限判断,所有权限验证必须由后端完成(前端可随意篡改JWT内容)。
  • 可通过解码后的exp字段(如果token包含)检查token是否过期,过期则清除存储并引导用户重新登录。

内容的提问来源于stack exchange,提问作者Arkar Phyo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 17:02:06