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

Express+JWT登录注册模块问题:中间件无法获取Token报错

问题分析与解决方案

核心错误点

  1. 变量作用域问题:中间件中token变量定义在第一个try块内部,属于块级作用域,后续的try块无法访问该变量,直接导致ReferenceError: token is not defined。
  2. Token获取逻辑错误:req.body || req.query || req.headers["x-access-token"]这种写法会返回整个req.body/req.query对象,而非其中的token字段,根本无法正确提取令牌。
  3. 表单跳转的Token传递缺失:普通HTML表单提交后执行redirect,新发起的GET请求不会自动携带之前生成的JWT令牌,导致/home路由的中间件完全拿不到令牌。

分步修复代码

1. 修复JWT验证中间件(auth.js)

const jwt = require('jsonwebtoken');
const config = process.env;

const verifyToken = (req, res, next) => {
    // 正确提取token:从body、query、headers的指定字段中获取
    let token = req.body.token || req.query.token || req.headers["x-access-token"];
    
    // 检查token是否存在
    if (!token) {
        return res.status(403).send("未找到令牌,请重新登录");
    }

    try {
        // 验证令牌并挂载到req对象
        const decoded = jwt.verify(token, config.TOKEN_KEY);
        req.user = decoded;
        console.log(req.user);
    } catch (error) {
        return res.status(401).send(`令牌验证失败:${error.message}`);
    }
    return next();
};

module.exports = verifyToken;

2. 修复登录/注册接口的Token传递逻辑

普通HTML表单跳转无法自动携带Token,推荐将Token存入HTTP Cookie(无需前端额外处理),修改登录和注册接口:

注册接口修改

app.post("/register", async (req, res) => {
    try { 
        const Username = req.body.Username;
        const email = req.body.email;
        const password = req.body.password;
       
        if (!(Username && email && password)) {
            return res.status(400).send("所有字段均为必填项!");
        }

        const oldUser = await User.findOne({ email });
        if (oldUser) {
            return res.status(409).send("用户已存在,请直接登录");
        }

        const encryptedPassword = await bcrypt.hash(password, 10);

        const user = await User.create({
            Username,
            email: email.toLowerCase(),
            password: encryptedPassword,
        });

        const token = jwt.sign(
            { user_id: user._id, email },
            process.env.TOKEN_KEY,
            { expiresIn: "2h" }
        );
        user.token = token;
        await user.save();

        // 将Token存入HttpOnly Cookie,防止XSS攻击
        res.cookie('token', token, { 
            httpOnly: true, 
            maxAge: 2 * 60 * 60 * 1000, // 2小时有效期
            secure: process.env.NODE_ENV === 'production' // 生产环境启用HTTPS
        });
        res.status(201).redirect('/home');
    } catch (error) {
        console.log(`注册错误:${error}`);
        res.status(500).send("服务器内部错误");
    }
})

登录接口修改

app.post("/login", async (req, res) => {
    try {
        const { email, password } = req.body;

        if (!(email && password)) {
            return res.status(400).send("请填写所有必填信息");
        }

        const user = await User.findOne({ email });
        if (user && (await bcrypt.compare(password, user.password))) {
            const token = jwt.sign(
                { user_id: user._id, email },
                process.env.TOKEN_KEY,
                { expiresIn: "2h" }
            );
            user.token = token;
            await user.save();

            // 将Token存入HttpOnly Cookie
            res.cookie('token', token, { 
                httpOnly: true, 
                maxAge: 2 * 60 * 60 * 1000,
                secure: process.env.NODE_ENV === 'production'
            });
            res.status(200).redirect('/home');
        } else {
            res.status(400).send("用户不存在或密码错误,请先注册");
        }

    } catch (error) {
        console.log(`登录错误:${error}`);
        res.status(500).send("服务器内部错误");
    }
})

3. 更新中间件的Token获取逻辑(支持从Cookie提取)

修改auth.js,增加从Cookie获取Token的逻辑:

const verifyToken = (req, res, next) => {
    // 新增从Cookie获取Token的方式
    let token = req.body.token || req.query.token || req.headers["x-access-token"] || req.cookies.token;
    
    if (!token) {
        return res.status(403).send("未找到令牌,请重新登录");
    }

    try {
        const decoded = jwt.verify(token, config.TOKEN_KEY);
        req.user = decoded;
        console.log(req.user);
    } catch (error) {
        return res.status(401).send(`令牌验证失败:${error.message}`);
    }
    return next();
};

4. 额外注意事项

  • 确保你的Express应用已经安装并引入了cookie-parser中间件,否则无法读取req.cookies:
    npm install cookie-parser
    
    在主文件中添加:
    const cookieParser = require('cookie-parser');
    app.use(cookieParser());
    
  • 主文件中你错误引入了const req = require("express/lib/request");,这会覆盖Express的req对象,导致请求处理异常,必须删除该行。

内容的提问来源于stack exchange,提问作者AMITSINH VIKRAMSINH RAJPUT

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 21:54:57