添加角色权限控制时出现TypeError: Cannot read properties of undefined (reading 'role')错误排查求助
嘿,我看你在给应用加角色权限控制的时候碰到了这个头疼的错误,咱们一步步拆解问题根源,把它搞定!
这个错误的核心原因很清晰:req.user是undefined,所以你没法读取它的role属性。咱们来看具体哪里出了问题以及怎么修复:
1. 问题根源:authenticateToken中间件没把用户信息挂载到req.user上
你的authenticateToken目前只做了一件事:验证token是否有效,但没有把解码后的用户信息或者数据库查询到的用户实例挂载到req对象的user属性上。后面的restrict中间件自然就拿不到req.user了。
看你当前的authenticateToken代码:
const authenticateToken = async (req, res, next) => { try { const token = req.cookies.jwt if(token){ jwt.verify(token,process.env.JWT_SECRET,(err)=>{ if(err){ console.log(err.message) res.redirect("/login") }else{ next() } }) }else{ res.redirect("/login") } } catch (error) { res.status(401).json({ succeded: false, error: "Not authorized" }) } };
这里调用jwt.verify时其实能拿到decodedToken(里面包含你生成token时传入的userId),但你没利用它去查询用户并挂载到req.user上。
修复authenticateToken
把它改成这样,参考你checkUser中间件的逻辑,查询用户并挂载到req.user:
const authenticateToken = async (req, res, next) => { try { const token = req.cookies.jwt if(token){ jwt.verify(token, process.env.JWT_SECRET, async (err, decodedToken) => { if(err){ console.log(err.message) res.redirect("/login") }else{ // 根据解码出的userId查询用户,挂载到req.user const user = await User.findById(decodedToken.userId); req.user = user; next() } }) }else{ res.redirect("/login") } } catch (error) { res.status(401).json({ succeded: false, error: "Not authorized" }) } };
2. 修复restrict中间件的逻辑漏洞
你当前的restrict中间件里,不管权限校验是否通过,都会执行next(),这会导致即使用户权限不够,也会继续执行后面的控制器代码,这是个逻辑bug。另外最好先判断req.user是否存在,避免再次触发类似的undefined错误。
修改后的restrict:
const restrict = (role) =>{ return(req,res,next)=>{ // 先检查req.user是否存在,防止未认证的情况 if(!req.user){ const error = new CustomError("No auth", 401); return next(error); } if(req.user.role !== role){ const error = new CustomError("No auth", 403) return next(error) } // 权限校验通过,继续执行 next() } }
注意这里用了return next(error),确保错误抛出后不会再执行后面的next()。
3. 额外检查:确认CustomError已正确导入
别忘了在authMiddleware.js顶部确认你已经导入了自定义的CustomError类,不然会触发新的错误。比如:
import CustomError from './path-to-your-custom-error-file.js';
做完这些修改后,再去访问/about页面,应该就能正常校验管理员权限,不会再出现那个TypeError了!
备注:内容来源于stack exchange,提问作者metkopetru

