Following this example: http://scotch.io/tutorials/javascript/easy-node-authentication-setup-and-local and everything works fine except the Flash messages part.
I have changed the view engine to Jade instead of EJS but I just can't seem to get the flash messages to show.
The code provided in the ejs view is:
<% if (message.length > 0) { %>
<div class="alert alert-danger"><%= message %></div>
<% } %>
and I would have thought that I could do this instead for Jade:
if #{message}
p message
or even:
if message
p message
but no success. Any idea what I'm doing wrong?
Note I have included all the necessary libraries as per the tutorial
Here's how I used flashes in Jade...
-if(messages)
div#note #{messages}
And use this to render your view, passing the messages var to your view
req.flash('info', "Credenciales invalidas, intente nuevamente");
res.render('index', {messages: req.flash('info')});
That works for me
I went ahead and used a custom callback like so:
app.post('/login', function(req, res, next) {
passport.authenticate('local-login', function(err, user, info) {
if (err) { return next(err); }
if (!user) { return res.render('login', {message: req.flash('loginMessage')}); }
req.logIn(user, function(err) {
if (err) { return next(err); }
return res.redirect('/users/' + user.username);
});
})(req, res, next);
});
This worked for me (as commented by #Xianlin). Routes:
app.get('/login', function(req, res) {
res.render('login', { message: req.flash('loginMessage') });
});
app.post('/login', urlencodedParser, passport.authenticate('local-login', {
successRedirect : '/profile',
failureRedirect : '/login',
failureFlash : true
}));
Return the required error message using Passport:
return done(null, false, req.flash('loginMessage', 'That email address does not exist'));
And finally in Jade:
if (message.length > 0)
#alert
p= message
Hope this helps!
Related
How can I pass parameter from Express route to A
`router.post('/login',
passport.authenticate('local', { failureRedirect: '/login' }),
function(req, res) {
res.locals.username=req.user.username;
res.redirect('/home');
});`
This is what I have in the route for Express. I want to pass the username from here to the frontend that I have done in Angular and echo it.
You should return a JSON versus redirects and in the front-end side catch the response to render it.
router.post('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) {
return res.json({ error: err });
}
if (!user) {
return res.json({ error: 'Authentication failed' });
}
req.logIn(user, function(err) {
if (err) {
return res.json(err);
}
return res.json({ username: user.username });
});
})(req, res, next);
});
I based in the Passport docs in the Authentication / Custom Callback section:
http://www.passportjs.org/docs/
After people log into my Express app, I'd like to redirect them to a url that reads:
www.mysite.com/:user
What I'm having trouble with is that my req.params object is coming up as an empty object literal when people get re-directed after logging in.
Ideally what I'd like to do is to somehow take the information stored in req.user and pass some of that information into the URL.
So basically I'd like to get from here:
router.post('/login',
passport.authenticate('local', {successRedirect:'/', failureRedirect: '/login', failureFlash: true}));
To here:
router.get('/:user', function(req, res) {
//stuff
}
After logging in the req.user object reads like this:
{
username: joesmith#mail.com,
name: Joe Smith,
password: dkei348#$kDL^583L,
formulas: []
}
And the code I'm attempting to use is as follows:
router.get('/:user', function(req, res) {
var user = req.user.name;
req.params = {
"user": user
}
But this doesn't work because initially req.user.name is undefined if someone isn't already logged in, so I can't get past the console error.
Apparently I don't understand how req.params is generated in enough detail to get around this problem.
Thank you.
If you want to have username in parameters you shoud redirect to '/' + req.user.name); because '/' doesn't have any params. That's why it is undefined. (additionaly you shoud check if parameter is defined and handle the error, so instead of console error you get error 404 or get to next, proper routing path).
Passport Documentation privides examples of doiung it:
app.post('/login',
passport.authenticate('local'),
function(req, res) {
// If this function gets called, authentication was successful.
// `req.user` contains the authenticated user.
res.redirect('/' + req.username);
});
or more complex custom callback :
app.get('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) { return next(err); }
if (!user) { return res.redirect('/login'); }
req.logIn(user, function(err) {
if (err) { return next(err); }
return res.redirect('/' + user.name);
});
})(req, res, next);
});
But I think it is not a good practice and safer would be to redirect to the proper page/content by req.user value without putting it to URL, for example setting req.auth. and then using next(); instead of res.redirect('/' + user.name); to get to the next middleware. There username would be taken from req.auth.username, not from /:username.
How does the structure of your routing looks? You shoud make sure router.get('/:user' .. is not before router.get('/login'...
Looks like you are wanting to access whatever /:user value is. e.g. www.mysite.com/stretch0. Therefore you would access it like var user = req.params.user;
You can provide a custom handler, instead of letting Passport do all the redirecting:
app.post('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) {
req.flash('error', 'Unable to authenticate user');
return res.redirect('/login');
}
if (! user) {
return res.redirect('/login');
}
req.logIn(user, function(err) {
if (err) {
req.flash('error', 'Unable to log in user');
return res.redirect('/login');
}
return res.redirect('/' + user.username);
});
})(req, res, next);
});
This does mean that each logged-in user gets their "personal" URL, because you're redirecting to /USERNAME. I'm not sure from your question if that's actually your intention.
I'm trying to make Node.js ajax authentication with passport.js, I want to show messages in /login page. I should use res.send in my passport strategy, then ajax call ended successfully will display success data to its page. But I can't guess how can I use res. in strategy. Please see below code,
login.ejs
<div id="messages"></div>
<!-- and there is a form, when form submitted, the ajax call executed.-->
<!-- ...ajax method : POST, url : /login, data: {}, success:... -->
<!-- If ajax call success, get 'result' data and display it here -->
app.js
// and here is ajax handler
// authentication with received username, password by ajax call
app.post('/login', passport.authenticate('local'),
function(req, res, next){
res.redirect('/');
});
// and here is passport strategy
passport.use(new passportLocal.Strategy(function(userid, password, done) {
Members.findOne({'user_id' : userid}, function(err, user){
// if user is not exist
if(!user){
// *** I want to use 'res.send' here.
// *** Like this :
// *** res.send('user is not exist');
// *** If it is possible, the login.ejs display above message.
// *** That's what I'm trying to it. How can I do it?
return done(null, null);
}
// if everything OK,
else {
return done(null, {id : userid});
}
})
}));
I searched some document on google, people usually use 'flash()' in connect-flash module, but I thought this module needed to reload page, this is not what I want to, So please help me and let me know if there is better way. Thanks.
Instead of directly inserting the Passport middleware, you can use a custom callback in order to pass the req, res, next objects to the Passport function.
You could do something similar in your route handler/controller (this is taken directly from the Passport docs):
app.post('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) { return next(err); }
if (!user) { return res.redirect('/login'); }
req.logIn(user, function(err) {
if (err) { return next(err); }
return res.redirect('/users/' + user.username);
});
})(req, res, next);
});
I'm having problem with sending a flash if authentication fails. Except that everything is OK. When I'm copying example (https://github.com/jaredhanson/connect-flash) to my app flash messages are working fine...
Here is my code:
//routes
app.get('/login', function (req,res){
res.render('login', {
authMessage: req.flash('authMessage')
});
});
app.post('/login', passport.authenticate('local', {
failureRedirect: '/login',
failureFlash: true
}), function(req,res){
res.send('ok');
});
//local strategy
passport.use(new LocalStrategy(
function(username, password, authCheckDone) {
UserDetails.findOne({username : username}).then(
function(user){
if (!user) {
console.log('bad username');
return authCheckDone(null, false, {authMessage: 'Wrong name'});
}
if (user.password !== password) {
console.log('bad password');
return authCheckDone(null, false, {authMessage: 'Wrong password'});
}
return authCheckDone(null, user);
}),
function(error){
return authCheckDone(error);
};
}
));
//ejs
<% if (authMessage.length > 0) { %>
<p>test</p>
<%= authMessage %>
<% } %>
I've read somewhere this problem may be related with security and not using https, but if that would be the case example from github wouldn't work either...
If I am not wrong, the callback you pass to LocalStrategy should have as first parameter the request object. So your function would look like this:
function(req, username, password, authCheckDone) {
// your code
After that, according to an example that I have, you should return the result of authCheckDone in the following way:
return authCheckDone(null, false, req.flash('authMessage', "your message"));
But make sure you create the LocalStrategy object in the following way:
new LocalStrategy({
passReqToCallback: true // don't forget this
}, function(req, username, password, authCheckDone) {
I have no login page but rather I have a login form that appears on every page. I want to redirect user back to the same page they were on regardless of whether authentication was successful (with appropriate flash messages)
Take the following code:
app.post('/login', validateLogin, passport.authenticate('local-login'), function(req, res) {
var redirectUrl = '/';
if(req.body.to.length > 0){
redirectUrl = req.body.to;
}
console.log("THIS IS ONLY CALLED IF passport.authenticate() IS SUCCESSFUL");
res.redirect(redirectUrl);
});
I only see the final middleware above being called if authentication is passed. If it fails then passport appears to be redirecting me to /login in the form of a get request. In my app this page doesn't exist.
If I pass an additional options object as a parameter in the passport authenticate function then this works:
app.post('/login', validateLogin, passport.authenticate('local-login', {
successRedirect : '/', // redirect to the secure profile section
failureRedirect : '/signup', // redirect back to the signup page. THIS IS JUST FOR TESTING TO SEE IF THE REDIRECT ON FAIL WORKS.
failureFlash : true, // allow flash messages
}
));
But in doing this I lose the ability to choose where to redirect the user to. It seems that passport takes control over where the user is redirected to if authentication fails. How can I fix this? Or is it a bug? Must passport authenticate be the last middleware in the chain if authentication fails?
This is my local strategy function call:
//LOCAL LOGIN
passport.use('local-login', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField : 'email',
passwordField : 'password',
passReqToCallback : true // allows us to pass back the entire request to the callback
},
function(req, email, password, done) { // callback with email and password from our form
console.log("IN PASSPORT");
if(email.length == 0 || password.length == 0){
console.log("FIELDS ARE EMPTY");
return done(null, false, req.flash('loginMessage', 'Fill in all values.'));
}
// find a user whose email is the same as the forms email
// we are checking to see if the user trying to login already exists
User.findOne({ 'local.email' : email }, function(err, user) {
// if there are any errors, return the error before anything else
if (err){
return done(err);
console.log("db err");
}
// if no user is found, return the message
if (!user){
console.log("not user");
return done(null, false, req.flash('loginMessage', 'Incorrect details.')); // 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)){
console.log("invalid pw");
return done(null, false, req.flash('loginMessage', 'Incorrect details.')); // create the loginMessage and save it to session as flashdata
}
// all is well, return successful user
console.log("All OK");
return done(null, user);
});
}));
You could use a custom authentication callback as described in the last paragraph there http://passportjs.org/guide/authenticate/.
app.post('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) { return next(err); }
// Redirect if it fails
if (!user) { return res.redirect('/login'); }
req.logIn(user, function(err) {
if (err) { return next(err); }
// Redirect if it succeeds
return res.redirect('/users/' + user.username);
});
})(req, res, next);
});
I was running into the same issue where the redirect-calls , that follow successful Facebook Auth
passport.authenticate('facebook', ..)
.. were not being honored.
Based on 'local' passportJS Strategy - and a nice reminder of that from #ploutch's answer here .. I realized the key to getting it to work seems to be in this call:
req.logIn(user, function(err) {
...
}
For Facebook, this route setup worked for me:
app.get(
'/auth/facebook/callback',
passport.authenticate
(
'facebook',
{ failureRedirect: '/fbFailed' }
),
function(req, res)
{
var user = myGetUserFunc(); // Get user object from DB or etc
req.logIn(user, function(err) {
if (err) {
req.flash('error', 'SOMETHING BAD HAPPEND');
return res.redirect('/login');
}
req.session.user = user;
// Redirect if it succeeds
req.flash('success', 'Fb Auth successful');
return res.redirect('/user/home');
});
}
);
Full answer, including:
Middleware to set redirectUrl
Flash messages
Not returning values that won't be used
Just create a redirectTo value in your loginRequired middleware:
var loginRequired = function(req, res, next) {
if ( req.isAuthenticated() ) {
next();
return
}
// Redirect here if logged in successfully
req.session.redirectTo = req.path;
res.redirect('/login')
}
And then in your login POST:
router.post('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if ( err ) {
next(err);
return
}
// User does not exist
if ( ! user ) {
req.flash('error', 'Invalid email or password');
res.redirect('/login');
return
}
req.logIn(user, function(err) {
// Invalid password
if ( err ) {
req.flash('error', 'Invalid email or password');
next(err);
return
}
res.redirect(req.session.redirectTo || '/orders');
return
});
})(req, res, next);
});
I know this might still be a problem for some people like me who tried all the suggested options without any success.
In my case, as it turned out, I was getting the error because my req.body object was always empty. I had my body parsing middleware set up correctly so it didn't make sense why this was happening.
After more research I found out that the enctype I was using for my forms(multipart/form-data) isn't supported by body-parser - see their read me - after switching to a different middleware, multer, everything worked smoothly.