When im logging in the req.user is displayed as it should, but after navigating to /test , the req.user is undefined.
Why is that?
server.js
var express = require('express'); // call express
var app = express(); // define our app using express
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
var session = require('express-session');
var router = express.Router();
var Account = require('src/app/models/Users.js');
var Core = require('/src/app/gamemodels/core');
// Init passport authentication
var passport = require('passport');
var Strategy = require('passport-local').Strategy;
require('/src/config/passport')(passport);
var cookieParser = require('cookie-parser')
// required for passport session
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
mongoose.connect('DB');
app.use(cookieParser()) // required before session.
app.use(session({ secret: 'xxxx' }));
app.use(passport.initialize());
app.use(passport.session());
var port = process.env.PORT || 3000; // set our port
// test route to make sure everything is working (accessed at GET http://localhost:8080/api)
router.get('/', function(req, res) {
res.json({ text: 'hooray! welcome to our api!' });
});
router.get('/test', function(req,res) {
console.log(req);
console.log(req.user);
res.json(req.user);
});
router.post('/signup', passport.authenticate('local-signup', {
successRedirect : '/profile', // redirect to the secure profile section
failureRedirect : '/signup', // redirect back to the signup page if there is an error
}));
router.post('/login', passport.authenticate('local-login'), function(req, res) {
console.log("executed login!");
console.log(req.user);
req.session.user = req.user;
});
});
*/
// more routes for our API will happen here
// REGISTER OUR ROUTES -------------------------------
// all of our routes will be prefixed with /api
app.use('/api', router);
// START THE SERVER
// =============================================================================
app.listen(port);
console.log('Magic happens on port ' + port);
passport js:
// config/passport.js
// load all the things we need
var LocalStrategy = require('passport-local').Strategy;
// load up the user model
var Account = require('src/app/models/Users.js');
// expose this function to our app using module.exports
module.exports = function(passport) {
passport.serializeUser(function(user, done) {
done(null, user);
});
// used to deserialize the user
passport.deserializeUser(function(id, done) {
Account.findById(id, function(err, user) {
done(err, user);
});
});
passport.use('local-login', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField : 'username',
passwordField : 'password',
passReqToCallback : true // allows us to pass back the entire request to the callback
},
function(req, username, password, done) { // callback with email and password from our form
console.log("doing local login");
// 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
Account.findOne({ 'username' : username }, function(err, user) {
var thisuser = user;
console.log("query account is done");
// if there are any errors, return the error before anything else
if (err) {
console.log("error occured");
return done(err);
}
console.log("if user exist check");
// if no user is found, return the message
if (!user)
return done(null, false,'No user found.'); // req.flash is the way to set flashdata using connect-flash
console.log("checking password");
// if the user is found but the password is wrong
if (!user.validPassword(password)) {
console.log("password is not valid");
return done(null, false, 'Oops! Wrong password.'); // create the loginMessage and save it to session as flashdata
}
console.log("all good! logging in!");
req.login(thisuser, function(error) {
if (error) return next(error);
console.log("Request Login supossedly successful.");
});
// all is well, return successful user
return done(null, thisuser);
});
}));
passport.use('local-signup', 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, username, password, done) {
process.nextTick(function() {
console.log("doing local signup");
// 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
Account.findOne({ 'username' : username }, function(err, user) {
// if there are any errors, return the error
if (err)
return done(err);
// check to see if theres already a user with that email
if (user) {
return done(null, false, 'That username is already taken.');
} else {
var newUser = new Account();
// set the user's local credentials
newUser.username = username;
newUser.password = newUser.encryptPassword(password);
// save the user
newUser.save(function(err) {
if (err)
throw err;
return done(null, newUser);
});
}
});
});
}));
};
EDIT1:
changed passport.js serialize function and deserialize function to the following:
passport.serializeUser(function(user, done) {
done(null, user.username);
});
// used to deserialize the user
passport.deserializeUser(function(username, done) {
Account.findOne({'username': username}, function(err, user) {
done(err, user);
});
});
still did not make any difference. Undefined still occur.
EDIT2:
value of user in serializing:
{ _id: 5909a6c0c5a41d13340ecf94,
password: '$2a$10$tuca/t4HJex8Ucx878ReOesICV6oJoS3AgYc.LxQqCwKSV8I3PenC',
username: 'admin',
__v: 0,
inFamily: false,
bank: 500,
cash: 2500,
xp: 0,
rank: 1,
bullets: 0,
location: 1,
permission: 0,
health: 100 }
edit3:
changed the login func to:
router.post('/login', passport.authenticate('local-login'), function(req, res) {
console.log("executed login!");
console.log(req.user);
req.session.user = req.user;
req.logIn(req.user, function (err) {
if (err) {
return next(err);
}
});
});
server log response:
doing local login
query account is done
if user exist check
checking password
all good! logging in!
serializing!
Request Login supossedly successful.
serializing!
executed login!
{ _id: 5909a6c0c5a41d13340ecf94,
password: '$2a$10$tuca/t4HJex8Ucx878ReOesICV6oJoS3AgYc.LxQqCwKSV8I3PenC',
username: 'admin',
__v: 0,
inFamily: false,
bank: 500,
cash: 2500,
xp: 0,
rank: 1,
bullets: 0,
location: 1,
permission: 0,
health: 100 }
serializing!
still no sign to unserialize log.
The reason is that you are missing on the deserialization part.
/**
* Each subsequent request will contain a unique
* cookie that identifies the session. In order to support login sessions,
* Passport will serialize and deserialize user instances to and from the session.
*/
passport.serializeUser(function (user, done) {
done(null, user.username);
});
passport.deserializeUser(function (username, done) {
/**
* Necessary to populate the express request object with
* the 'user' key
* Requires(*):
* - session support with express
* - call to logIn from passport.auth)enticate if using authenticate
* callback.
*/
// TODO: Verify if username exists
done(null, username);
});
So after the user is authenticated or when req.isAuthenticated() is true, the deserialization middleware function will be invoked and will update the request object with username or req.user in your case.
Reference:
passport js sessions
Since you are using a custom callback to handle success or failures, it becomes the application's responsibility to establish a session by calling req.logIn. So after the user is authenticated, add
req.logIn(user, function (err) {
if (err) { return next(err); }
return { // Do a redirect perhaps? }
});
Refer to section Custom Callbacks in the reference link, I gave you.
When defining methods and middleware on the passport object, order matters. Your code is pretty entangled. A little decoupling will go a long way here.
Move all of the strategy logic out of server.js and your passport.js. Put it in its own set of files. Also, you don't need to include the base Strategy in the server file.
Define an express router in a separate file and mount the routes in your server.js
passport.initialize() and passport.session() middlewares need to attach to your express app instance before you define serialize and deserialize.
No need to set req.session.user, which defeats the purpose of storing just the user id in the session. On each request to express, once you deserialize the user by reading the id in req.session.passport.user, you're loading the entire user account document into req.user and you can access all user data directly from req.user.
If you're using a pre-packaged passport Strategy constructor which calls done(), you don't need to call req.login anywhere.
server.js
//express, body parser, express session, etc
const app = express();
const passport = require('passport');
const user = require('./passport-serialize');
const routes = require('./routes');
//lots of middleware
//session middleware
app.use(passport.initialize());
app.use(passport.session());
passport.serializeUser(user.serialize);
passport.deserializeUser(user.deserialize);
app.use('/api', routes);
//actual server, more stuff
passport-serialize.js
//include Account model
const user = {
serialize: (user, done) => {
done(null, user.username)
},
deserialize: (username, done) => {
Account.findOne({'username': username}, function(err, user) {
done(err, user);
}
}
module.exports = user;
routes.js
const express = require('express');
const router = new express.Router();
const passport = require('./strategies');
//many routes
router.post('/login', passport.authenticate('local-login'), function(req, res) {
console.log("executed login!");
console.log(req.user);
});
router.get('/test', function(req, res) {
console.log(req.user);
res.json(req.user);
});
module.exports = router;
strategies.js
const passport = require('passport');
const LocalStrategy = require('whatever the package is');
//Account model
passport.use('local-login', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField : 'username',
passwordField : 'password',
passReqToCallback : true // allows us to pass back the entire request to the callback
}, function(req, username, password, done) { // callback with email and password from our form
console.log("doing local login");
// 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
Account.findOne({ 'username' : username }, function(err, user) {
var thisuser = user;
console.log("query account is done");
// if there are any errors, return the error before anything else
if (err) {
console.log("error occured");
return done(err);
}
console.log("if user exist check");
// if no user is found, return the message
if (!user)
return done(null, false,'No user found.');
// req.flash is the way to set flashdata using connect-flash
console.log("checking password");
// if the user is found but the password is wrong
} else if (!user.validPassword(password)) {
console.log("password is not valid");
return done(null, false, 'Oops! Wrong password.');
// create the loginMessage and save it to session as flashdata
}
console.log("all good! logging in!");
// all is well, return successful user
return done(null, thisuser);
});
}));
module.exports = passport;
Related
I'm having trouble with Passport.JS inside my Express app, more specifically the successful redirect for the registration/login. The username/password is being stored in DB without problems but the redirect in both cases is not working.
I'm using: Express, Body-Parser,, Mongoose, Passport, Passport-local and Passport-local-mongoose.
Passport Config
app.use(require("express-session")({
secret: "This is a test app",
resave: false,
saveUninitialized: false
}));
app.use(passport.initialize());
app.use(passport.session());
passport.use(new LocalStrategy(User.authenticate()));
passport.serializeUser(User.serializeUser);
passport.deserializeUser(User.deserializeUser);
Sign Up Route
app.post("/register", function(req, res) {
var newUser = new User({username: req.body.username});
User.register(newUser, req.body.password, function (err, user) {
if (err) {
console.log(err);
return res.render("register");
}
passport.authenticate("local"),(req, res, function(){
res.redirect("/campgrounds");
});
});
});
Login Route
app.post("/login",
passport.authenticate("local", {
successRedirect: "/campgrounds",
failureRedirect: "/login"
}));
Write this in your passport config
and try to match variables names to yours in your application
passport.use('local-signup', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField : 'usernameFORM',
passwordField : 'passwordFORM',
passReqToCallback : true // allows us to pass back the entire request to the callback
},
function(req, usernameCB, passwordCB, done) {
// asynchronous
process.nextTick(function() {
// Whether we're signing up or connecting an account, we'll need
// to know if the email address is in use.
User.findOne({'username' : usernameCB}, function(err, existingUser) {
// if there are any errors, return the error
if (err)
return done(err);
// check to see if there's already a user with that email
if (existingUser)
return done(null, false);
// If we're logged in, we're connecting a new account.
if(req.user) {
console.log(req.user);
var user = req.user;
User.username = usernameCB;
User.password = user.generateHash(passwordCB);
User.save(function(err) {
if (err)
throw err;
return done(null, user);
});
}
// We're not logged in, so we're creating a brand new user.
else {
// create the user
var User = new User();
User.username = usernameCB;
User.password = User.generateHash(passwordCB);
User.save(function(err) {
if (err)
throw err;
return done(null, user);
});
}});
});
}));
and in your routes
app.post('/signup',passport.authenticate('local-signup',{
successRedirect:'/campgrounds',
failureRedirect:'/login'
}))
Background:
I have a angular-cli running on port 4200, and server sided api node.js running on 3000.
I find out that the session passport value wont save after logging in with the passport-local.
so when i try to navigate to another page after logging in, its not holding the passport, variable in sessions as it is supposed to, required to call req.user
For some reason, the server is not calling deserialize user.
Req.user wont work after login and redirecting to page /test.
Update:
To login i send a request from site using port 4200, with the following code: (angular2/4)
performLogin(name: string, password: string): Observable<Comment[]> {
var params = new URLSearchParams();
params.append('username', name);
params.append('password', password);
url = "SITE:3000/api/login";
return this.http.post(this.url,params, this.options)
.map(result => result.json())
.do(result => this.result = result);
}
Update 2: inserted creditals request client sided.
On every request to login -> then calling test page i always get:
ReferenceError: User is not defined
at /root/mafiagame/src/config/passport.js:32:9
at pass (/usr/lib/node_modules/passport/lib/authenticator.js:347:9)
at Authenticator.deserializeUser (/usr/lib/node_modules/passport/lib/authenticator.js:352:5)
at SessionStrategy.authenticate (/usr/lib/node_modules/passport/lib/strategies/session.js:53:28)
at attempt (/usr/lib/node_modules/passport/lib/middleware/authenticate.js:348:16)
at authenticate (/usr/lib/node_modules/passport/lib/middleware/authenticate.js:349:7)
at Layer.handle [as handle_request] (/root/mafiagame/node_modules/express/lib/router/layer.js:95:5)
at trim_prefix (/root/mafiagame/node_modules/express/lib/router/index.js:317:13)
at /root/mafiagame/node_modules/express/lib/router/index.js:284:7
at Function.process_params (/root/mafiagame/node_modules/express/lib/router/index.js:335:12)
at next (/root/mafiagame/node_modules/express/lib/router/index.js:275:10)
at initialize (/usr/lib/node_modules/passport/lib/middleware/initialize.js:53:5)
at Layer.handle [as handle_request] (/root/mafiagame/node_modules/express/lib/router/layer.js:95:5)
at trim_prefix (/root/mafiagame/node_modules/express/lib/router/index.js:317:13)
at /root/mafiagame/node_modules/express/lib/router/index.js:284:7
at Function.process_params (/root/mafiagame/node_modules/express/lib/router/index.js:335:12)
Related issues, that did not fix my problem:
Passportjs not saving user into session after login
PassportJS deserializeUser never called
Express Passport Session not working
req.session.passport is empty, deserializeUser not called - ExpressJS, Passport
Main issue: Req.user wont work after login and redirecting to page /test.
It seems like the session is saved, but the passport details within that session, is not.
My application:
dump of req.session after login:
Session {
cookie:
{ path: '/',
_expires: 2017-05-03T19:42:58.728Z,
originalMaxAge: 14400000,
httpOnly: true,
secure: false },
passport: { user: '5909a6c0c5a41d13340ecf94' } }
session when visiting /test
Session {
cookie:
{ path: '/',
_expires: 2017-05-03T19:43:10.503Z,
originalMaxAge: 14400000,
httpOnly: true,
secure: false } }
server.js
here is my server.js with the express, passport etc.
var express = require('express'); // call express
var app = express(); // define our app using express
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
var session = require('express-session');
var router = express.Router();
var Account = require('src/app/models/Users.js');
var Core = require('src/app/gamemodels/core');
// Init passport authentication
var passport = require('passport');
var Strategy = require('passport-local').Strategy;
require('src/config/passport')(passport);
var cookieParser = require('cookie-parser')
app.use(function(req, res, next) {
res.header('Access-Control-Allow-Credentials', true);
res.header('Access-Control-Allow-Origin', req.headers.origin);
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept');
if ('OPTIONS' == req.method) {
res.send(200);
} else {
next();
}
});
// required for passport session
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
mongoose.connect('database');
app.use(cookieParser()) // required before session.
app.use(session({
secret: 'xxx',
cookie: {
secure: false
}}));
app.use(passport.initialize());
app.use(passport.session());
console.log(mongoose.connection.readyState);
app.use(function (req, res, next) {
console.log('Time:', Date.now());
// core.loggameRequest();
next();
});
var port = process.env.PORT || 3000; // set our port
// test route to make sure everything is working (accessed at GET http://localhost:8080/api)
router.get('/', function(req, res) {
res.json({ text: 'hooray! welcome to our api!' });
});
router.get('/test', function(req,res) {
console.log(req.user);
res.json(req.user);
});
router.get("/getuser", function(req,res) {
Account.findOne({}, function (err,response) {
console.log("starting core...");
console.log(Core);
console.log("core log end");
// Core.experienceToRankDetails(response.xp,'female');
console.log("executed!");
// res.json(response);
Core.experienceToRankDetails(response.xp,'female').then(function (result) {
res.json({user: response, rank: result});
});
});
});
router.get('/onlinestate', function(req,res) {
if (req.user) {
res.json(true);
} else {
res.json(false);
}
});
router.post('/signup', passport.authenticate('local-signup', {
successRedirect : '/profile', // redirect to the secure profile section
failureRedirect : '/signup', // redirect back to the signup page if there is an error
}));
router.post('/login', passport.authenticate('local-login'), function(req, res) {
console.log("executed login!");
console.log(req.user);
req.session.user = req.user;
req.logIn(req.user, function (err) { // have this in passport login too, but tried it here too .
if (err) {
return next(err);
}
});
});
/*
router.post('/login', function(req,res) {
console.log("routing post login");
console.log(req.body);
console.log(req.user);
var username = req.body.username;
var password = 0;
console.log("using passport");
passport.authenticate('local', {failureRedirect: '/login'}, function (req, res) {
console.log("performed!");
res.redirect('/');
});
});
*/
// more routes for our API will happen here
// REGISTER OUR ROUTES -------------------------------
// all of our routes will be prefixed with /api
app.use('/api', router);
*/
// START THE SERVER
// =============================================================================
app.listen(port);
console.log('Magic happens on port ' + port);
passport:
// config/passport.js
// load all the things we need
var LocalStrategy = require('passport-local').Strategy;
// load up the user model
var Account = require('src/app/models/Users.js');
// expose this function to our app using module.exports
module.exports = function(passport) {
passport.serializeUser(
function(user, done){
console.log("serialize");
done(null, user.id);
});
passport.deserializeUser(
function(id, done){
console.log("deserialize " + id);
Account.findById(id, function(err, user){
if(err){
done(err);
}
done(null, user);
});
});
passport.use('local-login', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField : 'username',
passwordField : 'password',
passReqToCallback : true // allows us to pass back the entire request to the callback
},
function(req, username, password, done) { // callback with email and password from our form
console.log("doing local login");
// 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
Account.findOne({ 'username' : username }, function(err, user) {
var thisuser = user;
console.log("query account is done");
// if there are any errors, return the error before anything else
if (err) {
console.log("error occured");
return done(err);
}
console.log("if user exist check");
// if no user is found, return the message
if (!user)
return done(null, false,'No user found.'); // req.flash is the way to set flashdata using connect-flash
console.log("checking password");
// if the user is found but the password is wrong
if (!user.validPassword(password)) {
console.log("password is not valid");
return done(null, false, 'Oops! Wrong password.'); // create the loginMessage and save it to session as flashdata
}
console.log("all good! logging in!");
req.login(thisuser, function(error) {
if (error) return next(error);
console.log(error);
console.log("Request Login supossedly successful.");
});
// all is well, return successful user
return done(null, thisuser);
});
}));
passport.use('local-signup', 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, username, password, done) {
process.nextTick(function() {
console.log("doing local signup");
// 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
Account.findOne({ 'username' : username }, function(err, user) {
// if there are any errors, return the error
if (err)
return done(err);
// check to see if theres already a user with that email
if (user) {
return done(null, false, 'That username is already taken.');
} else {
var newUser = new Account();
// set the user's local credentials
newUser.username = username;
newUser.password = newUser.encryptPassword(password);
// save the user
newUser.save(function(err) {
if (err)
throw err;
return done(null, newUser);
});
}
});
});
}));
};
user variable contains:
{ _id: 5909a6c0c5a41d13340ecf94,
password: '$2a$10$tuca/t4HJex8Ucx878ReOesICV6oJoS3AgYc.LxQqCwKSV8I3PenC',
username: 'admin',
__v: 0,
inFamily: false,
bank: 500000,
cash: 1,
xp: 0,
rank: 1,
bullets: 0,
location: 1,
permission: 0,
health: 100 }
response from server after logging in: (post to /login route)
doing local login
query account is done
if user exist check
checking password
all good! logging in!
serialize
undefined
Request Login supossedly successful.
serialize
executed login!
{ _id: 5909a6c0c5a41d13340ecf94,
password: '$2a$10$tuca/t4HJex8Ucx878ReOesICV6oJoS3AgYc.LxQqCwKSV8I3PenC',
username: 'admin',
__v: 0,
inFamily: false,
bank: 500000,
cash: 1,
xp: 0,
rank: 1,
bullets: 0,
location: 1,
permission: 0,
health: 100 }
serialize
server response from visiting /test
undefined
It seems to be an angular 2/4 issue. you can try this this or this
Hope it can help you! :-)
I've added nodejs passport login to my app and everything worked fine, until I committed changes to production. The issue is pretty wired: user is randomly changes sometimes when I reload the page.
Here is my app.js code:
var mysql = require('promise-mysql');
var passport = require('passport');
var app = express();
app.use(cookieParser())
app.use(session({
secret: 'keyboard cat',
maxAge: 60 * 5,
resave: false,
saveUninitialized: false
}))
app.use(passport.initialize());
app.use(passport.session());
mysql.createConnection(dbConfig.connection).then(
function (connection) {
require('./config/passport')(passport, connection); // pass passport for configuration
}
);
Here is what I have in configs/passport.js
var LocalStrategy = require('passport-local').Strategy;
var bcrypt = require('bcrypt-nodejs');
module.exports = function (passport, connection) {
passport.serializeUser(function (user, done) {
done(null, user.name);
});
// used to deserialize the user
passport.deserializeUser(function (name, done) {
connection.query("SELECT * FROM users WHERE name = ? ", [name])
.then(function (rows) {
done(null, rows[0]);
})
.catch(function (err) {
console.log("Error getting user form DB: ", err);
done(err);
});
});
passport.use(
'local-login',
new LocalStrategy({
usernameField: 'username',
passwordField: 'password',
passReqToCallback: true // allows us to pass back the entire request to the callback
},
function (req, username, password, done) { // callback with email and password from our form
connection.query("SELECT * FROM users WHERE username = ?", [username])
.then(function (rows) {
if (!rows.length) {
done(null, false); // req.flash is the way to set flashdata using connect-flash
}
// if the user is found but the password is wrong
else if (!bcrypt.compareSync(password, rows[0].password)) {
done(null, false); // create the loginMessage and save it to session as flashdata
// all is well, return successful user
}
else {
done(null, rows[0]);
}
})
.catch(function (err) {
console.log("Login Failed: ", err.body);
done(err);
});
})
);
};
And this is what I have in every route file:
router.all('*', function (req, res, next) {
if (req.isAuthenticated()) {
user.init(req.user);
next(); // pass control to the next handler
}
else {
res.redirect('/');
}
});
Does anyone had similar issue? Seems like I've made some simple and stupid error, because google can't find similar issues.
Thanks!
You're executing two different queries:
// passport.deserializeUser()
connection.query("SELECT * FROM users WHERE name = ? ", [name])
// In the Passport verification handler
connection.query("SELECT * FROM users WHERE username = ?", [username])
My guess would be that name isn't unique, and that you want to use username everywhere.
As an aside: you're setting maxAge to 300 milliseconds.
Turns out to be issue with objects storing by node js in memory. I don't fully understand how this is happened, but this is what I found.
I stored req.user in userModel object, and if there are a lot of requests on server, this userModel object sometimes gets messed up with data from different users.
The solution was to directly user req.user everywhere.
I'm getting an error in Node.js when I try to login or signup.
I'm using connect-mongodb-session, but when I setup an store, it happen.
serializing user:
{ _id: 57cf316758531915c8a93dd7,
email: 'a',
password: '$2a$10$1.qkrnLWLiG6zFXHTII1pOsHs0sWdFrmfgaGO.6ZY4q/TwZ7E0RTG',
username: 'a',
followers: [],
following: [],
likes: [],
orders: [],
__v: 0 }
POST /login 302 793.072 ms - 46
_http_outgoing.js:344
throw new Error('Can\'t set headers after they are sent.');
^
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:344:11)
at ServerResponse.header (C:\Users\Fabian Gutierrez\Documents\GitHub\maravillarte\node_modules\express\lib\response.js:718:10)
at ServerResponse.send (C:\Users\Fabian Gutierrez\Documents\GitHub\maravillarte\node_modules\express\lib\response.js:163:12)
at done (C:\Users\Fabian Gutierrez\Documents\GitHub\maravillarte\node_modules\express\lib\response.js:957:10)
at Immediate._onImmediate (C:\Users\Fabian Gutierrez\Documents\GitHub\maravillarte\node_modules\express-handlebars\lib\utils.js:26:13)
at processImmediate [as _immediateCallback] (timers.js:383:17)
Error: Can't set headers after they are sent.
I tried a lot of thing, but I don't understand what happens
this is my code, app.s:
var passport = require('passport');
var expressSession = require('express-session');
var MongoDBStore = require('connect-mongodb-session')(expressSession);//session for stores sessions
//MONTAR EL STORE DE SESSIONS
var mystore = new MongoDBStore(dbConfig.store,function(error) {
if (error){
console.log(error)
}
});
app.use(expressSession({
cookie:{ maxAge: 1000 * 60 * 60 * 24 * 7 },
httpOnly: true,
store: mystore,
secret: 'mifuckingkey',
resave: true,
saveUninitialized: false,
unset: 'destroy'
}));
app.use(passport.initialize());
app.use(passport.session());
// Using the flash middleware provided by connect-flash to store messages in session
// and displaying in templates
var flash = require('connect-flash');
app.use(flash());
// Inicializar Passport
var initPassport = require('./lib/passport/init');
initPassport(passport);
var routes = require('./routes/index')(passport);
app.use('/', routes);
init.js
var login = require('./login');
var signup = require('./signup');
var User = require('../../models/user');
module.exports = function(passport){
// Passport needs to be able to serialize and deserialize users to support persistent login sessions
passport.serializeUser(function(user, done) {
console.log('serializing user: ');console.log(user);
done(null, user._id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
console.log('deserializing user:',user);
done(err, user);
});
});
console.log("passport iniciado")
// Setting up Passport Strategies for Login and SignUp/Registration
login(passport);
signup(passport);
}
signup.js
var LocalStrategy = require('passport-local').Strategy;
var User = require('../models/user');
var bCrypt = require('bcrypt-nodejs');
module.exports = function(passport){
passport.use('login', new LocalStrategy({
passReqToCallback : true
},
function(req, username, password, done) {
// check in mongo if a user with username exists or not
User.findOne({ 'username' : username },
function(err, user) {
// In case of any error, return using the done method
if (err)
return done(err);
// Username does not exist, log the error and redirect back
if (!user){
console.log('User Not Found with username '+username);
return done(null, false, req.flash('message', 'User Not found.'));
}
// User exists but wrong password, log the error
if (!isValidPassword(user, password)){
console.log('Invalid Password');
return done(null, false, req.flash('message', 'Invalid Password')); // redirect back to login page
}
// User and password both match, return user from done method
// which will be treated like success
return done(null, user);
}
);
})
);
var isValidPassword = function(user, password){
return bCrypt.compareSync(password, user.password);
}
}
signup.js
var LocalStrategy = require('passport-local').Strategy;
var User = require('../../models/user');
var bCrypt = require('bcrypt-nodejs');
module.exports = function(passport){
passport.use('login', new LocalStrategy({
passReqToCallback : true
},
function(req, username, password, done) {
// check in mongo if a user with username exists or not
User.findOne({ 'username' : username },
function(err, user) {
// In case of any error, return using the done method
if (err)
return done(err);
// Username does not exist, log the error and redirect back
if (!user){
console.log('User Not Found with username '+username);
return done(null, false, req.flash('message', 'User Not found.'));
}
// User exists but wrong password, log the error
if (!isValidPassword(user, password)){
console.log('Invalid Password');
return done(null, false, req.flash('message', 'Invalid Password')); // redirect back to login page
}
// User and password both match, return user from done method
// which will be treated like success
return done(null, user);
}
);
})
);
var isValidPassword = function(user, password){
return bCrypt.compareSync(password, user.password);
}
}
and part of router
router.get('/', function(req, res, next) {
res.render('home', { title: 'Maravillarte',user:req.user});
});
router.get('/vender', function(req, res, next) {
res.render('register', { title: 'Express',layout:'register' });
});
/*///////////////////////////////////////
INICIO DE SESSION
///////////////////////////////////////*/
router.post('/login', passport.authenticate('login', {
successRedirect: '/',
failureRedirect: '/',
failureFlash: true,
}));
router.get('/login', function(req, res, next) {
res.render('pages/login', { title: 'Maravillarte',user:req.user});
});
/*///////////////////////////////////////
REGISTRARSE
///////////////////////////////////////*/
router.post('/signup', passport.authenticate('signup', {
successRedirect: '/',
failureRedirect: '/',
failureFlash: true
}));
in your init.js,
// Setting up Passport Strategies for Login and SignUp/Registration
login(passport);
signup(passport);
Both routes res.render send the response back to the client asynchronously. So, when second route tries to send the response with res.render response of the first route already been sent. That's why it throws error like can't set header after they are sent.
follow the given link below for the example.
I was playing around with node.js as a beginner and trying to get the login/atuthentication running but got stuck there. I then downloaded connect-flash middleware using npm and this is how my server.js looks like:
var express = require('express'),
passport = require('passport'),
util = require('util'),
LocalStrategy = require('passport-local').Strategy,
wines = require('./routes/wines');
var users = [
{ id: 1, username: 'bob', password: 'secret', email: 'bob#example.com' }
, { id: 2, username: 'joe', password: 'birthday', email: 'joe#example.com' }
];
function findById(id, fn) {
var idx = id - 1;
if (users[idx]) {
fn(null, users[idx]);
} else {
fn(new Error('User ' + id + ' does not exist'));
}
}
function findByUsername(username, fn) {
for (var i = 0, len = users.length; i < len; i++) {
var user = users[i];
if (user.username === username) {
return fn(null, user);
}
}
return fn(null, null);
}
// Passport session setup.
// To support persistent login sessions, Passport needs to be able to
// serialize users into and deserialize users out of the session. Typically,
// this will be as simple as storing the user ID when serializing, and finding
// the user by ID when deserializing.
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
findById(id, function (err, user) {
done(err, user);
});
});
// Use the LocalStrategy within Passport.
// Strategies in passport require a `verify` function, which accept
// credentials (in this case, a username and password), and invoke a callback
// with a user object. In the real world, this would query a database;
// however, in this example we are using a baked-in set of users.
passport.use(new LocalStrategy(
function(username, password, done) {
// asynchronous verification, for effect...
process.nextTick(function () {
// Find the user by username. If there is no user with the given
// username, or the password is not correct, set the user to `false` to
// indicate failure and set a flash message. Otherwise, return the
// authenticated `user`.
findByUsername(username, function(err, user) {
if (err) { return done(err); }
if (!user) { return done(null, false, { message: 'Unknown user ' + username }); }
if (user.password != password) { return done(null, false, { message: 'Invalid password' }); }
return done(null, user);
})
});
}
));
var flash = require('connect-flash');
var express = require("express");
var app = express();
app.get('/', function(req, res){
res.render('index', { user: req.user });
});
app.get('/flash', function(req, res){
req.flash('info', 'Flash is back!')
res.redirect('/');
});
app.get('/account', ensureAuthenticated, function(req, res){
res.render('account', { user: req.user });
});
app.get('/login', function(req, res){
res.render('login', { user: req.user, message: "Hello!"});
});
// configure Express
app.configure(function() {
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.use(express.logger());
app.use(express.cookieParser());
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.session({ secret: 'keyboard cat' }));
// Initialize Passport! Also use passport.session() middleware, to support
// persistent login sessions (recommended).
app.use(passport.initialize());
app.use(passport.session());
app.use(app.router);
app.use(express.cookieParser('keyboard cat'));
app.use(express.session({ cookie: { maxAge: 60000 }}));
app.use(flash());
});
// POST /login
// Use passport.authenticate() as route middleware to authenticate the
// request. If authentication fails, the user will be redirected back to the
// login page. Otherwise, the primary route function function will be called,
// which, in this example, will redirect the user to the home page.
//
// curl -v -d "username=bob&password=secret" http://127.0.0.1:3000/login
app.post('/login',
passport.authenticate('local', { failureRedirect: '/login', failureFlash: true }),
function(req, res) {
res.redirect('/');
});
app.get('/logout', function(req, res){
req.logout();
res.redirect('/');
});
app.listen(3000);
// Simple route middleware to ensure user is authenticated.
// Use this route middleware on any resource that needs to be protected. If
// the request is authenticated (typically via a persistent login session),
// the request will proceed. Otherwise, the user will be redirected to the
// login page.
function ensureAuthenticated(req, res, next) {
if (req.isAuthenticated()) { return next(); }
res.redirect('/login')
}
app.get('/wines', wines.findAll);
app.get('/wines/:id', wines.findById);
console.log('Listening on port 3000...');
Why do I still get that error? How to fix it?
Move all your app[METHOD] middleware to after all the app.use middleware