【问题标题】:Calling next() at the end of custom middleware causes error在自定义中间件末尾调用 next() 会导致错误
【发布时间】:2021-05-24 18:43:06
【问题描述】:

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

为此,我使用 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() 函数。如果您能告诉我我在这里做错了什么,我将非常感谢您的帮助...

【问题讨论】:

    标签: node.js express cookies jwt


    【解决方案1】:

    您的验证部分错过了中间件中正确的错误处理。如果令牌无效,那么用户为什么要访问控制器,您可以从中间件本身发送错误。如果您没有从中间件发送错误并调用 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
    }
    

    【讨论】:

      【解决方案2】:

      您的jwt.verify 有一个异步回调,底部的next() 在返回之前被调用。因此,您要么需要将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() 被调用,却没有意识到需要等待回调或它可能处理的任何事情。

      【讨论】:

        猜你喜欢
        • 2018-05-18
        • 2018-07-13
        • 2021-06-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-12-25
        • 1970-01-01
        相关资源
        最近更新 更多