J'utilise passport.js et j'aimerais envoyer un message flash si les champs de mon formulaire sont vides. Mais je ne sais pas comment le faire car passeport ne déclenche pas le rappel de la stratégie si ceux-ci manquent. Je souhaite vraiment que ce cas d'utilisation soit plus clair et je ne souhaite pas modifier le passeport. J'ai l'impression qu'il y a un moyen de le faire mais je ne sais pas où! J'ai essayé d'utiliser le rappel de la route (app.post
), mais cela ne semble pas fonctionner comme j'ai essayé.
Voici le prototype de la fonction d'authentification:
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);
}
};
Voici ma stratégie:
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);
});
}));
Et enfin mon itinéraire:
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");
}));
Vous ne devez pas appeler req.flash
dans votre rappel de vérification. À la place, vous devriez renvoyer un message comme indiqué dans la documentation . Passport mettra le message renvoyé au message flash lorsque failureFlash: true
.
Votre rappel de vérification révisé:
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);
});
}));
Et des itinéraires:
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
}));
Modifier:
Voici un exemple pleinement fonctionnel: https://Gist.github.com/vesse/9e23ff1810089bed4426
C'est une vieille question, mais j'ai eu du mal à trouver une réponse. Espérons que cela aide les autres.
Je pense que la documentation est un peu incomplet en ce qui concerne l'utilisation de connect-flash
. Ils disent:
Remarque: L'utilisation de messages flash nécessite une fonction req.flash (). Express 2.x fournit cette fonctionnalité, mais elle a été supprimée d’Express 3.x. L'utilisation du middleware connect-flash est recommandée pour fournir cette fonctionnalité lors de l'utilisation d'Express 3.x.
Pourtant, il n'est pas question d'utiliser req.flash dans le rappel done()
. D'après le tutoriel scotch.io }, vous devez en fait appeler [] req.flash()
à cet endroit du rappel. Ça marche pour moi.
// In your strategy
...
if (user) {
return done( null, false, req.flash('loginMessage','Pas d\'utilisateur avec ce login.') );
...
Vous devrez utiliser passReqToCallback
bien sûr. Assurez-vous également que failureFlash
est défini sur true
. OP les fait déjà correctement.
Maintenant, vous pouvez vérifier le message flash dans l'itinéraire. Notez que connect-flash
envoie un tableau de messages. Cela pourrait être un problème pour OP, si son modèle attend une chaîne.
// 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!
});
});
S'il y a une chance que plusieurs messages de connexion soient présents sur une page, transmettez l'ensemble du tableau req.flash('loginMessage')
et parcourez-le dans votre modèle. Ci-dessous, un exemple utilisant nunjucks .
Protip:
Si vous avez plusieurs itinéraires avec des messages flash, vous pouvez toujours les définir sur res.locals
dans un itinéraire de logiciel intermédiaire. Cela n'interférera pas avec les autres sections locales, comme title
. Voici mon implémentation, en utilisant alertes d'amorçage .
Dans ma stratégie:
...
if (!user){
return done( null, false, req.flash('danger','No account exists for that email.') );
}
...
Dans mes 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'});
});
Dans mon modèle de base 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 %}
Vous devez définir badRequestMessage
et failureFlash: true
.
Comme ça:
passport.authenticate('login', {
successRedirect : '/',
failureRedirect : '/login',
badRequestMessage : 'Missing username or password.',
failureFlash: true
})
Après avoir passé des mois à essayer de faire fonctionner le flash en panne, j'ai finalement trouvé une solution qui n'utilise pas la fonctionnalité failureFlash. J'ai essentiellement créé un nouvel itinéraire et envoyé le message flash.
app.post('/login',
passport.authenticate('local', {failureRedirect: "/loginfailed"}),
function(req, res) {
if (!req.user.isActive){
req.flash("success","Your account needs to be verified. Please check your email to verify your account");
req.logout();
res.redirect("back")
}else{
res.redirect("/");
}
});
//Route to login page if user failed to login. I created this to allow flash messages and not interfere with regular login route
app.get("/loginfailed", function(req, res){
if (!req.user){
req.flash("success", "Username or password is incorrect.");
res.redirect("/login");
}
});
Lorsque les champs requis pour l'authentification sont manquants, passport.authenticate
ne déclenchera pas le rappel de stratégie, comme le souligne l'OP.
Cela doit être géré dans le custom callback (page de défilement vers le bas) dans la fonction d’authentification en utilisant le paramètre info
.
Dans le cas du code de l'OP comme ceci:
app.post('/login', function (req, res, next) {
passport.authenticate('local-login',
{
successRedirect: '/profile',
failureRedirect: '/login',
failureFlash: true,
},
function (error, user, info) {
//This will print: 'Missing credentials'
console.log(info.message);
//So then OP could do something like
req.flash(info.message);
//or in my case I didn't use flash and just did
if (info)
res.status(400).send(info.message);
...
})(req, res, next);
});
Je sais que cette question est ancienne mais je suis tombé sur cette question moi-même et je constate qu'il n'y a toujours pas de réponse acceptée. De plus, je pense que toutes les réponses ont mal interprété ce que le PO demandait réellement: un moyen d'accéder à badRequestMessage
.
Les documents PassportJS ne sont pas très utiles non plus:
Si l'authentification échoue, l'utilisateur sera défini sur false. Si une exception survient, err sera défini. Un argument d'information facultatif sera passé, contenant des détails supplémentaires fournis par le rappel de vérification de la stratégie.
Cela signifie en réalité que le paramètre info
peut être passé en tant que troisième paramètre de votre stratégie, comme suit: done(error,user,info)
, mais ne mentionne pas que ce paramètre est utilisé par défaut en cas d'informations manquantes. Globalement, je pense que les documents de PassportJS pourraient faire l’objet d’une refonte car ils manquent de détails et/ ils renvoient à des exemples non existants .
Cette réponse m'a aidé à comprendre que le message d'informations d'identification manquantes est transmis dans le paramètre info
.