在自定义中间件末尾调用 next() 会导致错误

Calling next() at the end of custom middleware causes error

我正在尝试设置 viewpages 以在登录时在页面上显示经过身份验证的用户的信息,例如用户名或电子邮件。

为此,我使用 res.locals 函数在全局级别设置用户数据以供页面访问。

const jwt = require("jsonwebtoken")
const User = require("../models/User")

const checkUser = (req, res, next) => {
    const token = req.cookies.jwt
    if (token) {
        jwt.verify(token, "Company_Special_Code", async (err, decodedToken) => {
            if (err) {
                res.locals.user = null // Set it to null if the user does not exist
                next();
            } else {
                let user = await User.findById(decodedToken.id)
                res.locals.user = user
                next();
            }
        })
    } else {
        res.locals.user = null
        next();
    }
}

module.exports = {
    checkUser
}

第一个代码,每次代码到达端点时调用 next() 函数,允许页面访问用户信息而不会出现任何错误。

但是,如果我只在 checkUser() 函数的最底部调用 next() 函数一次,则会导致错误,声称用户未在视图页面级别定义。代码如下:

const jwt = require("jsonwebtoken")
const User = require("../models/User")

const checkUser = (req, res, next) => {
    const token = req.cookies.jwt
    if (token) {
        jwt.verify(token, "Company_Special_Code", async (err, decodedToken) => {
            if (err) {
                res.locals.user = null // Set it to null if the user does not exist
            } else {
                let user = await User.findById(decodedToken.id)
                res.locals.user = user
            }
        })
    } else {
        res.locals.user = null
    }
    next();
}

module.exports = {
    checkUser
}

如果我正确地编写了函数代码,无论 jwt 令牌的状态如何,或者令牌验证过程中是否出现错误,checkUser() 函数都应该到达底部的 next() 函数。如果您能告诉我我在这里弄错了什么,我将非常感谢您的帮助...

您的验证部分错过了中间件中正确的错误处理。如果令牌无效,那么用户为什么要访问控制器,您可以从中间件本身发送错误。如果您没有从中间件发送错误并调用 next(),那么您的身份验证中间件的目的就会失败。
按如下方式更新您的代码,

const jwt = require("jsonwebtoken")
const User = require("../models/User")
// The routes, which does not requires aurthentication
const usecuredRoutes = []
const checkUser = (req, res, next) => {
if(usecuredRoutes.indexOf(req.path) === -1){
    const token = req.cookies.jwt
    if (token) {
        jwt.verify(token, "Company_Special_Code", async (err, decodedToken) => {
            if (err) {
                res.locals.user = null // Set it to null if the user does not exist
// Token is invalid, then telll user that he is don't have access to the resource
                res.status(403).send('Unauthorized')
            } else {
                let user = await User.findById(decodedToken.id)
                res.locals.user = user
                next();
            }
        })
    } else {
// Token does not exists, then telll user that he is don't have access to the resource
      res.status(403).send('Unauthorized')
    }
} else {
  next()
}
}

module.exports = {
    checkUser
}

您的 jwt.verify 有一个异步回调,底部的 next() 在 returns 之前被调用。因此,您要么需要将 next() 放入该回调,要么同步使用 jsonwebtoken。像这样:

const checkUser = (req, res, next) => {
  const token = req.cookies.jwt
  if (token) {
    try {
      const decodedToken = jwt.verify(token, "Company_Special_Code")
      // This only runs if the token was decoded successfully
      let user = await User.findById(decodedToken.id)
      res.locals.user = user
    } catch (error) {
      res.locals.user = null // Set it to null if the user does not exist
    }
  } else {
    res.locals.user = null
  }
  next();
}

当您使用这样的异步回调时,javascript 将继续处理脚本的其余部分,而该回调 运行 在一边(或多或少)。所以 next() 被调用时没有意识到需要等待回调或它可能处理的任何事情。