使用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
相关产品推荐
相关产品推荐

