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 })