Node.js使用Passport进行身份validation:如果字段丢失,如何刷新消息?

我正在使用passport.js,如果我的表单的字段是空的,我想要显示一条消息。 但是我不知道该怎么做,因为护照没有触发策略callback。 我真的希望这个用例更清楚,我不想修改护照。 我觉得有办法这样做,但我不知道在哪里! 我试图使用路由( app.post )的callback,但它似乎并没有按照我的方式工作。

这里是身份validation函数原型:

 Strategy.prototype.authenticate = function(req, options) { options = options || {}; var username = lookup(req.body, this._usernameField) || lookup(req.query, this._usernameField); var password = lookup(req.body, this._passwordField) || lookup(req.query, this._passwordField); // here is my problem if (!username || !password) { return this.fail({ message: options.badRequestMessage || 'Missing credentials' }, 400); } var self = this; function verified(err, user, info) { if (err) { return self.error(err); } if (!user) { return self.fail(info); } self.success(user, info); } try { if (self._passReqToCallback) { this._verify(req, username, password, verified); } else { this._verify(username, password, verified); } } catch (ex) { return self.error(ex); } }; 

这是我的策略:

  passport.use('local-login', new LocalStrategy({ usernameField : 'email', passwordField : 'password', passReqToCallback : true }, function(req, email, password, done) { // ... console.log("Hello"); User.findOne({ 'local.email' : email }, function(err, user) { if (err) return done(err); // if no user is found, return the message if (!user) return done(null, false, req.flash('loginMessage', 'Pas d\'utilisateur avec ce login.')); // req.flash is the way to set flashdata using connect-flash // if the user is found but the password is wrong if (!user.validPassword(password)) return done(null, false, req.flash('loginMessage', 'Oops! Mauvais password.')); // create the loginMessage and save it to session as flashdata // all is well, return successful user return done(null, user); }); })); 

最后我的路线:

 app.get('/login', function(req, res) { // render the page and pass in any flash data if it exists res.render('login', { title: "Connexion", message: req.flash('loginMessage') }); }); // process the login form app.post('/login', passport.authenticate('local-login', { successRedirect : '/profile', // redirect to the secure profile section failureRedirect : '/login', // redirect back to the signup page if there is an error failureFlash : true // allow flash messages }, function(err, user, info) { // Was trying this callback, does'nt work, post callback maybe ? console.log("Hello"); })); 

你不应该在你的validationcallback中调用req.flash 。 相反,您应该返回一个消息,如文档中所示 。 failureFlash: true时,护照会将消息返回给flash消息。

您修改后的validationcallback:

 passport.use('local-login', new LocalStrategy({...}, function(email, password, done) { User.findOne({ 'local.email' : email }, function(err, user) { if (err) return done(err); if (!user) return done(null, false, {message: 'Pas d\'utilisateur avec ce login.'}); if (!user.validPassword(password)) return done(null, false, {message: 'Oops! Mauvais password.'}); return done(null, user); }); })); 

和路线:

 app.get('/login', function(req, res) { console.log(req.flash('error')); res.send(); }); app.post('/login', passport.authenticate('local-login', { successRedirect : '/profile', failureRedirect : '/login', failureFlash : true })); 

编辑:

这是一个完整的工作示例: https : //gist.github.com/vesse/9e23ff1810089bed4426

这是一个古老的问题,但我很难find答案。 希望这可以帮助别人。


我认为使用connect-flash时文档有点不完整。 他们说:

注意:使用flash消息需要一个req.flash()函数。 Express 2.x提供了此function,但已将其从Express 3.x中删除。 使用Express-3.x时,build议使用连接闪存中间件来提供此function。

然而,在done()callback中没有提到使用req.flash。 基于scotch.io教程 ,您实际上应该在callback中调用req.flash() 。 这个对我有用。

 // In your strategy ... if (user) { return done( null, false, req.flash('loginMessage','Pas d\'utilisateur avec ce login.') ); ... 

当然你需要使用passReqToCallback 。 还要确保failureFlash设置为true 。 OP已经正确地做了这些。

现在您可以查看路由中的Flash信息。 请注意, connect-flash发送一组消息 。 这可能是OP的问题,如果他的模板期望一个string。

 // In your routes app.get('/login', function(req, res) { // Test flash messages in the console console.log( req.flash('loginMessage') ); // This returns an array console.log( req.flash('loginMessage')[0] ); // This returns a string // render the page and pass in any flash data if it exists res.render('login', { title: "Connexion", message: req.flash('loginMessage')[0] // Don't forget the index! }); }); 

如果有可能在页面上有多个login消息,则传递整个req.flash('loginMessage')数组并在模板中遍历它。 下面是一个使用nunjucks的例子。


专家提示:

如果有许多路由与闪存消息,您可以随时将它们设置为中间件路由中的res.locals 。 这不会干扰其他当地人,如title 。 这是我的实现,使用引导警报 。

在我的策略中:

 ... if (!user){ return done( null, false, req.flash('danger','No account exists for that email.') ); } ... 

在我的routes.js中:

 // Set flash messages router.get('*', function(req,res,next){ res.locals.successes = req.flash('success'); res.locals.dangers = req.flash('danger'); res.locals.warnings = req.flash('warning'); next(); }); // Login route app.get('/login', function(req, res) { res.render('login', { title: 'Login'}); }); 

在我的nunjucks基础模板中:

 <!--Messages--> {% for danger in dangers %} <div class='header alert alert-danger alert-dismissible'> <strong><i class="fa fa-exclamation-circle"></i> ERROR:</strong> {{ danger | safe }} <a href="#" class='close' data-dismiss="alert" aria-label="close"><i class='fa fa-times'></i></a> </div> {% endfor %} {% for warning in warnings %} <div class='header alert alert-warning alert-dismissible'> <strong><i class="fa fa-check-circle"></i> Warning:</strong> {{ warning | safe }} <a href="#" class='close' data-dismiss="alert" aria-label="close"><i class='fa fa-times'></i></a> </div> {% endfor %} {% for success in successes %} <div class='header alert alert-success alert-dismissible'> <strong><i class="fa fa-check-circle"></i> Success!</strong> {{ success | safe }} <a href="#" class='close' data-dismiss="alert" aria-label="close"><i class='fa fa-times'></i></a> </div> {% endfor %} 

你需要设置badRequestMessage并设置failureFlash: true

喜欢这个:

 passport.authenticate('login', { successRedirect : '/', failureRedirect : '/login', badRequestMessage : 'Missing username or password.', failureFlash: true })