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

基于Node.js+Express+JWT+Sequelize的认证服务获取用户失败问题

问题:JWT认证后获取当前用户接口返回“User not found”

使用Node.js、Express.js、JWT和Sequelize开发API认证服务,登录接口可成功返回token,但携带token请求/api/auth/me接口时,收到“User not found”错误。


相关代码

路由文件 routes/api/auth.js

const express = require('express');
const router = express.Router();
const { protect } = require('../../middleware/auth'); 

const {
    register,
    login,
    getMe,
} = require('../../controllers/auth');

router.post('/register', register);
router.post('/', login);
router.get('/me', protect, getMe);

module.exports = router;

控制器方法

//@route   POST api/auth
//@desc    Authenticate user & get token
//@access  public

exports.login = asyncHandler(async (req, res, next) => {
    const { email, password } = req.body;

    //Validate email and password
    if(!email || !password){
        return res.status(400).json({ errors: [{ msg: 'Please provide an email and password'}]});
    }

    //See if user exists
    let user = await User.findOne({ where: { email: email }, attributes: ['email', 'password'] });

    if(!user){
        return res.status(400).json({ errors: [{ msg:'Invalid credentials' }] });
    }

    //Compare the input password, plane text, to the encrypted password.
    const isMatch = await user.matchPassword(password);
    
    if(!isMatch){
        return res.status(401).json({ errors: [{ msg:'Invalid credentials' }] });
    }

    //Return jsonwebtoken -> this for users to be logged in right after registration
    sendTokenResponse(user, 200, res);

});

//@desc   Get current logged in user
//@route  GET api/auth/me
//@access Private

exports.getMe = asyncHandler(async (req, res, next) => {
    const user = await User.findByPk(req.user.id);

    res.status(200).json({
        success: true,
        data: user
    });
})

//Get Token from model, create a cookie and send response

const sendTokenResponse = (user, statusCode, res) => {
    // Create token
    const token = user.getSignedJwtToken();
  
    const options = {
      expires: new Date(
        Date.now() + process.env.JWT_COOKIE_EXPIRE * 24 * 60 * 60 * 1000
      ),
      httpOnly: true
    };
  
    if (process.env.NODE_ENV === 'production') {
      options.secure = true;
    }
  
    res
      .status(statusCode)
      .cookie('token', token, options)
      .json({
        success: true,
        token
      });
  };

路由保护中间件

const jwt = require('jsonwebtoken');
const asyncHandler = require('./async');
const ErrorResponse = require('../utils/errorResponse');
const User = require('../models/User.model');

//Protect Routes 
exports.protect = asyncHandler(async (req, res, next) => {
    let token;

    if (req.headers.authorization && req.headers.authorization.startsWith('Bearer')) {
        token = req.headers.authorization.split(' ')[1];
    } else if (req.cookies.token) {
        token = req.cookies.token;
    }

    //Make sure token exists
    if(!token){
        return next(new ErrorResponse('Not authorized to access this route', 401));
    }

    try {
        const decoded = jwt.verify(token, process.env.JWT_SECRET);
        const user = await User.findByPk(decoded.id);
        if (!user) {
            return next(new ErrorResponse('User not found', 404));
        }
        req.user = user;
        next();
    } catch (error) {
        return next(new ErrorResponse('Not authorized to access this route', 401));
    }
});

User模型的签名方法

User.prototype.getSignedJwtToken = function() {
    return jwt.sign({ id: this.id }, process.env.JWT_SECRET, {
       expiresIn: process.env.JWT_EXPIRE
    });
}; 

问题原因与修复方案

核心问题

在login方法查询用户时,指定了attributes: ['email', 'password'],导致返回的user对象缺失id字段。而生成JWT的getSignedJwtToken方法依赖this.id,此时this.id为undefined,最终JWT中存储的id是undefined。后续protect中间件用decoded.id查询用户时自然找不到,返回“User not found”。

修复步骤

  1. 修改登录接口的用户查询逻辑:移除attributes限制,或者明确包含id字段:
// 方案1:获取用户所有字段
let user = await User.findOne({ where: { email: email } });

// 方案2:仅获取需要的字段(包含id)
let user = await User.findOne({ 
  where: { email: email }, 
  attributes: ['id', 'email', 'password'] 
});
  1. 可选优化:减少重复数据库查询:protect中间件已经查询到用户并挂载到req.user,getMe方法可直接返回该对象,无需再次查询:
exports.getMe = asyncHandler(async (req, res, next) => {
  res.status(200).json({
    success: true,
    data: req.user
  });
})

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 02:45:00