MVC重构Node.js项目时出现Cannot read properties of undefined (reading 'admin')错误求助
问题排查与解决方案
错误根源
出现TypeError: Cannot read properties of undefined (reading 'admin')的核心原因是:
- 控制器未将
req/res参数传递给用例函数,导致用例中req为空对象,无法读取req.user - 路由存在重复定义,部分逻辑被覆盖
- 用例层直接处理响应渲染,违背MVC职责划分
分步修复
1. 修正控制器的参数传递与职责
控制器需要接收请求上下文req/res,并将用户信息传递给用例,最后负责视图渲染:
// controller/todos/index.js const TODOS = require("../../models/usecases/todo"); module.exports = { getAllTodos: async (req, res) => { try { console.log("in the controller"); // 传递当前用户给用例,而非空对象 const todos = await TODOS.getAllTodos(req.user); // 根据用户身份渲染对应页面 if (req.user.admin) { res.render("admin-dashboard.ejs", { todoTasks: todos, user: req.user, }); } else { res.render("todo.ejs", { todoTasks: todos, user: req.user, }); } } catch (error) { console.error(error); res.status(500).send("获取待办事项失败"); } }, // 其他方法保持不变 };
2. 重构用例层的业务逻辑
用例层仅负责数据查询,返回业务数据,不处理HTTP响应:
// models/usecases/todo.js const TodoTask = require("../../models/entity/ToDoTask"); const getAllTodos = async function (user) { if (user.admin === true) { // 使用await替代回调,符合async函数规范 return await TodoTask.find({}); } else { return await TodoTask.find({ "user.id": user._id }); } }; module.exports = { getAllTodos };
3. 修复路由重复定义问题
路由中/admin-dashboard被定义两次,后续路由会覆盖前面的。合并认证与权限校验逻辑:
// 路由文件 "use strict"; const express = require("express"); const router = express.Router(); const { ensureAuthenticated, forwardAuthenticated, } = require("../controller/authentication/index"); const { isAdmin } = require("../controller/authentication/adminAuthMiddleware"); const { getAllTodos, createTodo, getTodo, editTodo, deleteTodo, } = require("../controller/todos/index"); // Welcome Page router.get("/", forwardAuthenticated, (req, res) => res.render("landing")); // 用户仪表盘:需登录 router.get("/dashboard", ensureAuthenticated, getAllTodos); // 管理员仪表盘:需登录+管理员权限 router.get("/admin-dashboard", ensureAuthenticated, isAdmin, getAllTodos); router.post("/dashboard", createTodo); router.route("/edit/:id").get(getTodo).post(editTodo); router.route("/remove/:id").get(deleteTodo); module.exports = router;
4. 验证认证中间件有效性
确保ensureAuthenticated中间件正确将用户信息挂载到req.user,示例实现:
// controller/authentication/index.js module.exports.ensureAuthenticated = (req, res, next) => { if (req.isAuthenticated()) { return next(); } req.flash('error_msg', '请先登录'); res.redirect('/login'); };
若req.user仍为undefined,需检查Passport.js的序列化/反序列化配置是否正确。
内容的提问来源于stack exchange,提问作者Syed Shuja Shah
相关产品推荐
相关产品推荐

