Owner认证权限异常:餐厅Dashboard无法正常访问
权限认证问题修复方案
问题场景
使用mysql2开发时,Owner已关联对应餐厅,但无法访问该餐厅的Dashboard。日志显示req.owner.id与restaurant.owner_id数值均为7,但权限判断if (req.owner && req.owner.id === restaurant.owner_id)不通过。
数据库表关联规则:
owner表以user_id为外键关联user表主键restaurant表以owner_id为外键关联owner表主键,支持一个Owner管理多家餐厅
核心原因分析
从中间件代码和日志可以确定:req.owner.id实际为undefined,导致与restaurant.owner_id(数字7)不匹配。
在isLoggedInAdmin中间件中,db.promise().query返回格式是[结果行数组, 字段信息],你通过const [owner] = await db.promise().query(...)将结果行数组赋值给了owner变量(日志显示Owner found: [ { id: 7, user_id: 42 } ],owner是数组),但后续直接取owner.id——数组没有id属性,因此req.owner.id为undefined,自然无法匹配数字7。
修复步骤
1. 修正中间件的Owner数据获取逻辑
修改isLoggedInAdmin中间件中Owner查询和赋值的代码:
exports.isLoggedInAdmin = async (req, res, next) => { console.log('isLoggedInAdmin middleware called'); if (req.cookies.one) { try { const decode = await jwt.verify(req.cookies.one, process.env.JWT_SECRET); // 获取用户信息,解构后取数组第一个元素 const [userRows] = await db.promise().query("SELECT * FROM user WHERE id = ?", [decode.id]); const user = userRows[0]; if (!user) { return res.status(401).json({ message: "Unauthorized" }); } // 获取Owner信息,同样取数组第一个元素 const [ownerRows] = await db.promise().query("SELECT * FROM owner WHERE user_id = ?", [decode.id]); const owner = ownerRows[0]; if (!owner) { return res.status(401).json({ message: "Unauthorized" }); } if (user.id !== owner.user_id) { return res.status(401).json({ message: "Unauthorized" }); } console.log('Owner found:', owner); req.owner = { id: owner.id, user_id: owner.user_id, }; next(); } catch (error) { console.error(error); return res.status(401).json({ message: "Unauthorized" }); } } else { console.log('No owner found'); next(); } };
2. 可选:优化路由查询性能
原路由中两次查询数据库可合并为一次关联查询,减少数据库请求次数:
router.get('/restaurants/:name/:location/dashboard', userContoller.isLoggedInAdmin, async (req, res) => { const restaurantName = req.params.name; const restaurantLocation = req.params.location; console.log(`restaurantName: ${restaurantName}`); console.log(`restaurantLocation: ${restaurantLocation}`); try { // 一次查询获取餐厅及对应Owner信息 const [rows] = await db.promise().query( `SELECT r.*, o.* FROM restaurant r JOIN owner o ON r.owner_id = o.id WHERE r.name = ? AND r.location = ?`, [restaurantName, restaurantLocation] ); if (!rows.length) { return res.render('errors/no permission'); } const restaurant = rows[0]; console.log(`restaurant: ${JSON.stringify(restaurant)}`); // 权限判断 if (req.owner && req.owner.id === restaurant.owner_id) { res.render('role/admin/index', { owner: { id: restaurant.id, user_id: restaurant.user_id }, restaurant }); } else { console.log('Owner not granted access to dashboard'); res.render('errors/no permission'); } } catch (error) { console.error(error); res.sendStatus(500); } });
额外优化建议
- 登录逻辑中
redirect("/restaurants/:name/:location/dashboard")是无效的,:name和:location是路由参数占位符,需要替换为用户实际管理的餐厅名称和地址,否则会跳转到字面量路径 - 权限判断前先校验
restaurant是否存在,避免因餐厅不存在导致restaurant.owner_id报错
内容的提问来源于stack exchange,提问作者Fabian
相关产品推荐
相关产品推荐

