当在 passport.js 登录周期中创建完全缺少凭据错误时

when exactly missing credentials error created in passport.js login cycle

我决定使用 passport.js 对我的节点应用程序进行身份验证。我实施了登录和注册的本地策略,它们工作正常,但有一个问题让我感到困惑。我过去构建了一个模块,它使用 http-error 包生成 returns http 错误。我用它来标准化错误生成。例如,如果某些凭据丢失或无效,我会致电 Errors.ValidationError({name:"password",reason:"password field is missing in your request"})

这会创建并 returns 正确的 http 错误,我将其发送给用户。它对于错误生成很有用。我想将此逻辑与护照一起使用,因此我选择创建自己的回调。这是一些代码:

本地登录策略定义

/**
 * User login
 * @param {*} request
 * @param {*} response
 * @return {*} logged existant user or error
 */
passport.use('login',
    new localStrategy(
        {
            usernameField: 'email',
            passwordField: 'password',
        },
        async (email, password, done)=> {
            if(email==null||password==null)
            {
                AppLogger.debug(21)
                return done(null, false);
            }
            User.findOne({ email: email }).
            then(async(user)=>{
                if (!user) {
                    AppLogger.debug(22)
                    return done(null, false);
                }
                if (!(await user.verifyPassword(password))) {
                    AppLogger.debug(23)
                    return done(null, false);
                }
                return done(null, user);
            }).
            catch((err)=>{
                AppLogger.debug(24)
                return done(err);
            });
        }
    )
);

登录路径

/**
 * Login an existant user
 */
AuthRouter.post('/login', (req, res, next)=> {
    passport.authenticate('login', (err, user, info) =>{
        if (err) {
            AppLogger.debug(1)
            return next(err);
        }
        if (!user) {
            AppLogger.debug(2)
            return next(info);
        }
        req.login(user,(err)=>{
            if(err){
                AppLogger.debug(3)
                return next(err);
            }
            res.send({
                success:true,
                message:"logged in"
            })
        })
    })(req, res, next);
});

考虑到代码中的所有调试行,我得到了这个输出: logs

我的日志行打印 2,这意味着没有异常,但用户为空,我试图了解在登录策略中确切创建了缺少凭据错误的位置,以便我可以生成自定义 http 错误。奇怪的是 none 策略中的调试没有被执行。请注意,有一个中间件可以捕获所有错误和日志,因此错误日志来自那里。并且保持实物应用程序按预期工作,但我无法发现此错误的产生位置。我假设护照中间件中的某些方法抛出错误,我的日志中间件捕获了它,但我如何与它交互并以有意义的方式生成我的 http 错误?任何建议表示赞赏。

这是我想出的解决方法:

路由器

/**
 * Login an existant user
 */
AuthRouter.post('/login', (req, res, next)=> {
    if(!req.body.email || !req.body.password){
        const subErrors = []
        if(!req.body.email){
            subErrors.push({
                name:"email",
                reason:"login request must contain email"
            })
        }
        if(!req.body.password){
            subErrors.push({
                name:"password",
                reason:"login request must contain password"
            })
        }
        const httpError = Errors.ValidationError(subErrors);
        return next(httpError);
    }
    passport.authenticate('login', (err, user, info) =>{
        if (err) {
            return next(err);
        }
        if (!user) {
            return next(info);
        }
        req.login(user,(err)=>{
            if(err){
                return next(err);
            }
            res.send({
                success:true,
                message:"logged in"
            })
        })
    })(req, res, next);
});

由于最终目标是用我的自定义 http 错误替换 passport 的默认丢失凭据错误,而且我在 passportjs 策略中找不到方法,所以我在调用 passport.authenticate() 之前检查了请求正文 我可以成功创建并 return 我的自定义错误,但这意味着尽管我手动检查,passportjs 也会检查凭据是否存在。所以它不是最佳的性能。

我也知道使用

if(x===null)

在某些情况下会导致一些问题,我也在原始代码中使用了'=='而不是'==='。它与主要问题无关,但不是最佳实践。

最后是默认和自定义错误响应:

这就是passportjs returns

{"message":"Missing credentials"}

这是我的自定义错误

{
"statusCode":400,
"error":"Bad Request",
"invalid_params":[
   {
       "name":"password",
       "reason":"login request must contain password"
   }
],
"type":"about:blank",
"title":"invalid parameters"}

我希望我能很好地解释我想要实现的目标。现在一切都按预期工作,但正如我所说的这个逻辑,我正在检查同一件事两次,所以如果有更好的解决方案,我们将不胜感激。