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

使用express-session认证用户时遇TypeError:无法读取user_id属性

Express-Session用户认证报错:TypeError: Cannot read properties of undefined (reading 'user_id')

问题详情

使用express-session实现用户认证时,持续触发以下错误:

TypeError: Cannot read properties of undefined (reading 'user_id')

逻辑上代码看似无问题,但无法定位解决该错误。以下是认证控制器、中间件及Session配置的完整代码:

AuthController代码

const authenticateUser  = require('../middleware/loginMiddleware');
const UserModel = require('../models/User');
const validator = require('validator');

const checkValid = async (req, res) => {
    const { email, password } = req.body;

    if (validator.isEmail(email) === false) {
        return res.status(400).render('../views/auth/login.ejs', { 'error': 'Error: Invalid email' });
    }

    try {
        const user = await UserModel.findOne({ email, password });

        if (user) {
            authenticateUser(req, res, user);
        } else {
            res.status(400).render('../views/auth/login.ejs', { 'error': 'Invalid login credentials' });
        }
    } catch (error) {
        console.log(error);
        res.status(500).render('../views/auth/login.ejs', { 'error': 'An error occurred while checking login credentials' });
    }
};

module.exports = {
    checkValid
};

认证中间件与Session配置代码

const express = require('express');
const session = require('express-session');
const sessionCookieLifeTime = 1000 * 60 * 15;
const cookieParser = require('cookie-parser')
const router = express.Router();

// Set up session middleware
router.use(session({
    secret: "+G2xQz%]/Lk)A8oN*W%xReKj=EcenJ",
    saveUninitialized: true,
    cookie: { maxAge: sessionCookieLifeTime },
    resave: false
}));
router.use(cookieParser());

// Middleware to check if the user is logged in
const checkLogin = (req, res, next) => {
    if (req.session && req.session.user_id) {
        // User is logged in, proceed to the next middleware or route
        next();
    } else {
        // User is not logged in, redirect to the login page or handle it accordingly
        res.redirect('/admin');
    }
};

const authenticateUser = (req, res, User) => {
    if (req.session && req.session.user_id) {
        return res.redirect('/dashboard');
    }

    if (User.email === req.body.email && User.password === req.body.password) {
        req.session.user_id = User._id; 
        console.log('\x1b[32mMessage:\x1b[0m Successfully authenticate user');
        console.log('\x1b[34mSession User id:\x1b[0m ' + req.session.user_id);
        return res.status(200).redirect('/dashboard');
    } else {
        console.log('\x1B[31mError:\x1b[0m', 'Invalid credentials.')
        return res.status(400).render('../views/auth/login.ejs', { 'error': 'Invalid credentials.' });
    }
};

module.exports = {
    authenticateUser,
    checkLogin,
};

问题原因及解决方案

1. 中间件顺序错误

express-session依赖cookie-parser解析请求中的cookie,因此cookieParser必须在session中间件之前加载。当前代码先初始化session再加载cookieParser,导致session无法正确初始化,req.session可能为undefined。

修正后的中间件顺序:

// 先加载cookieParser
router.use(cookieParser());
// 再初始化session
router.use(session({
    secret: "+G2xQz%]/Lk)A8oN*W%xReKj=EcenJ",
    saveUninitialized: true,
    cookie: { maxAge: sessionCookieLifeTime },
    resave: false
}));

2. Session中间件挂载级别问题

当前session中间件仅挂载在路由实例上,若主应用未正确挂载该路由,或其他路由需要使用session,建议将session和cookieParser挂载在全局应用级别,确保所有请求都经过session初始化:

在主app文件中修改:

const express = require('express');
const session = require('express-session');
const cookieParser = require('cookie-parser');
const app = express();

// 全局加载cookieParser和session
app.use(cookieParser());
app.use(session({
    secret: "+G2xQz%]/Lk)A8oN*W%xReKj=EcenJ",
    saveUninitialized: true,
    cookie: { maxAge: 1000 * 60 * 15 },
    resave: false
}));

// 挂载业务路由
app.use('/your-route-path', require('./path/to/your/router'));

3. 冗余代码与安全性优化

  • 禁止在数据库存储明文密码,使用bcrypt等工具哈希密码,验证时对比哈希值而非明文
  • authenticateUser中重复验证邮箱密码属于冗余操作,checkValid已通过UserModel.findOne匹配到用户,可直接跳过该判断

优化后的authenticateUser:

const authenticateUser = (req, res, User) => {
    if (req.session?.user_id) { // 使用可选链操作符避免undefined报错
        return res.redirect('/dashboard');
    }

    req.session.user_id = User._id; 
    console.log('\x1b[32mMessage:\x1b[0m Successfully authenticate user');
    console.log('\x1b[34mSession User id:\x1b[0m ' + req.session.user_id);
    return res.status(200).redirect('/dashboard');
};

4. 增强代码健壮性

使用可选链操作符?.代替逻辑与判断,可避免因req.session为undefined触发的报错:

// 原代码
if (req.session && req.session.user_id) { ... }

// 优化后
if (req.session?.user_id) { ... }

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 03:57:01