Passport JS自定义回调调用3次

问题描述:

我正在构建一个带有护照js的快速js api,并且为了能够返回格式为json的自定义错误消息,我使用的是custom callbacksPassport JS自定义回调调用3次

当我提供未知的电子邮件时,我写的自定义回调被称为3次,导致Unhandled rejection Error: Can't set headers after they are sent.。这是有道理的。

任何帮助表示赞赏。

这是我实现:

策略:

const localLoginStrategy = new LocalStrategy({ 
    usernameField: "emailAddress" 
}, (emailAddress, password, done) => { 
    // Called once 
    User.findOne({ 
     where: { emailAddress } 
    }).then((existingUser) => { 
     // Called once 
     if (!existingUser) { return done(null, false, { message: "Invalid email/password combination", status: 401 }); } 

     return existingUser.comparePassword(password); 
    }).then((userData) => { 
     return done(null, userData); 
    }).catch((err) => { 
     return done(null, false, { message: "Invalid email/password combination", status: 401 }); 
    }); 
}); 

passport.use(localLoginStrategy); 

快递中间件使用自定义回调验证:

const requireUsernamePassword = (req, res, next) => { 
    if(!req.body.emailAddress || !req.body.password) { 
     return res.status(400).json({ message: "No emailAddress and/or password provided" }); 
    } 
    // Called once 
    passport.authenticate("local", { session: false }, (err, user, info) => { 
     // Called three times! 
     console.log("authenticate callback") 
     if (!user || err) { 
      return res 
       .status(info.status || 400) 
       .json({ message: info.message || "Authentication error" }); 
     } 
     req.user = user; 
     return next(); 
    })(req, res, next); 
}; 
+0

什么叫您的requireUsernamePassword中间件?多个呼叫是否可以从呼叫堆栈的前面来?你可以尝试添加一个令人失望的User.findOne(....)'我怀疑它是来自那个,但它可以伤害,并且通常(并不总是)很好的做法来返回承诺。您是否记录了每个3次调用的err/user/info的值? – Boris

您的done函数多次调用。

我相信当你在then方法调用return done(...),未来then会再打电话done

所以这就是为什么你的callback功能从requireUsernamePassword被更多地按时调用。

希望它有帮助。

+0

我一直在努力奋斗,虽然我在你回答的时候已经明白了,但这是正确的答案。 – Alexander

要检查您的强制请求主体字段创建一个通用中间件,将检查必填字段并返回适当的返回码。就像下面一样。

module.exports = function checkParams(params) { 
    params = params || []; 
    return function(req, res, next) { 
    var valid = true; 
    if(Array.isArray(params)) { 
     params.forEach(function(_param) { 
     valid = valid && !!req.body[_param]; 
     }); 
    } 
    if (valid) { next() } else {return res.status(400).end();} //this is for missing required parameters 
    }; 
}; 

现在让我们说,例如,你有两个API。登录和CreateUser。 API应该途径看起来像下面

app.post('/Login', checkParams(['emailAddress', 'password']), passport.authenticate('local', { failureRedirect: '/login' }), actualLoginMethod); 


app.post('/CreateUser', checkParams(['userName', 'Phone']), passport.authenticate('local', { failureRedirect: '/login' }), actualCreateUserMethod); 

如果这些参数(在/登录用户名和电话/ CREATEUSER + EMAILADDRESS和密码)的缺失则它会返回400种状态,并从该点停止执行,你可能根据需要更改checkParams的逻辑。

如果需要的参数可用,那么它将检查JWT本地策略。一旦请求通过两个检查点,它就会调用实际的方法。

希望这可能会帮助你。

+0

我喜欢你的想法,但它不是我遇到的问题。不过我会执行check params函数。 – Alexander