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

Node.js认证中间件中如何将用户数据传递至后续路由处理函数?

Node.js认证中间件中如何将用户数据传递至后续路由处理函数?

Hey there! Let's break down why your currentUser was coming up undefined and how to properly pass user data to your buyCourse handler.

问题出在哪?

你最初的代码里,数据库查询是放在db.getConnection和connection.query的回调函数里的——这俩都是异步操作!但你后面判断!currentUser、给req.user赋值的代码是同步执行的,也就是说,当代码走到这些逻辑的时候,数据库查询还没跑完呢,currentUser自然就是undefined啦。

你修改后的代码方向是对的,但可以更优雅

你改用了jwt.verify的回调,把数据库查询嵌套进去,这确实解决了异步顺序的问题,但回调嵌套多了容易变成“回调地狱”,维护起来麻烦。咱们可以用async/await把异步代码改得更清晰,同时也能确保每一步都执行完再走下一步。

优化后的完整代码示例

先把数据库操作改成Promise形式(用Node.js自带的util.promisify包装),这样就能用async/await了:

const util = require('util');
const jwt = require('jsonwebtoken');
const mysql = require('mysql');
// 假设你的db是已经配置好的数据库连接池

// 把回调式的方法转成Promise形式
const getConnection = util.promisify(db.getConnection).bind(db);

exports.protect = async (req, res, next) => {
  try {
    // 1) 获取并校验token是否存在
    let token;
    if (req.headers.authorization && req.headers.authorization.startsWith("Bearer")) {
      token = req.headers.authorization.split(" ")[1];
    } else if (req.cookies.jwt) {
      token = req.cookies.jwt;
    }

    if (!token) {
      return res.status(401).json({
        status: "fail",
        message: "You are not logged in. Please login to get access",
      });
    }

    // 2) 验证token有效性
    const decoded = jwt.verify(token, process.env.JWT_SECRET);
    if (!decoded) {
      return res.status(403).json({ status: "fail", message: "Token invalid" });
    }

    // 3) 检查用户是否仍存在于数据库
    const connection = await getConnection();
    // 把query方法也转成Promise形式,绑定当前连接
    const query = util.promisify(connection.query).bind(connection);
    
    const sqlSearch = "SELECT * FROM users WHERE id = ?";
    const searchQuery = mysql.format(sqlSearch, [decoded.id]);
    // 查询结果是数组,取第一个元素(因为用户id唯一)
    const [currentUser] = await query(searchQuery);
    
    connection.release(); // 释放数据库连接

    if (!currentUser) {
      return res.status(401).json({
        status: "fail",
        message: "The user belonging to this token no longer exists",
      });
    }

    // 关键一步:把用户数据挂载到req对象上
    req.user = currentUser;
    res.locals.user = currentUser;
    next(); // 调用下一个中间件/路由处理函数
  } catch (err) {
    // 统一处理错误
    res.status(500).json({ status: "error", message: err.message });
  }
};

后续路由处理函数怎么用?

在你的buyCourse函数里,直接通过req.user就能拿到用户数据了:

exports.buyCourse = async (req, res) => {
  // 获取当前登录用户
  const loggedInUser = req.user;
  console.log("正在购买课程的用户:", loggedInUser);
  
  // 这里写你的课程购买逻辑,比如校验用户余额、生成订单等
  // ...
  
  res.status(200).json({
    status: "success",
    message: "Course purchased successfully",
    data: { /* 订单数据等 */ }
  });
};

小提示

  • 一定要记得在异步操作出错的时候处理错误,用try/catch包裹是个好习惯;
  • 数据库连接用完要记得释放,避免连接池耗尽;
  • 用mysql.format来拼接SQL语句,能防止SQL注入哦~

备注:内容来源于stack exchange,提问作者Szymon Tymuła

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.22 11:53:02