passportjs and passportlocal add users "Error: failed to serialize user into session" - database

I have followed the code here - > https://github.com/jaredhanson/passport-local/tree/master/examples/express3 for add local authentication for users.
The problem is when I try to add users,
So I created this route
app.get('/signup', function(req,res){
res.render('/signup');
});
app.post('/signup', function(req,res){
var body = req.body;
users.push(body);
res.redirect('/');
});
Then the page w the form It's
form(method='POST', action='/signup')
input(type='text', name='username', placeholder='username')
input(type='text', name='password', placeholder='password')
button.btn Register
The dummy DB It's the one on the example
users = [
{id:1, username: 'test', password:'papapa'}
];
So when I send the info w the form, all goes ok, but when I try to log in with the new created user, tells me "Error: failed to serialize user into session"
the serializeUser is this
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
findById(id, function (err, user) {
done(err, user);
});
});

The user being pushed in the POST /signup route will not have an ID, which the examples serialization code expects.
Change it to something like this, and it should work.
app.post('/signup', function(req,res){
var body = req.body;
body.id = users.length;
users.push(body);
res.redirect('/');
});
(Note that this is an example only, and not recommended for "real" apps.)

I guess you are missing the session serializer. Take a look to https://github.com/jaredhanson/passport, section 'Sessions'.
Basically, you need two functions, to save the current user into the session (passport.serializeUser) and to read it back (passport.deserializeUser).

Related

Angularjs : server side templating

I am very new to MEAN. And I have made an application using node.js, express and mongodb. I want to send username to dashboard after user is logged in. How can I do it using Angularjs. I don't want to use ejs templating engine. If any Middle ware is required....plzz tell me.
thank you...
this is my usercrud.js
var User = require("../../schema/user/userschema");
var bcrypt = require('bcrypt');
const userOperation={
login(userObject,response){
var username=userObject.userid;
var psw = userObject.password;
User.find({ userid:username}, function (err, user) {
if (err) {
return done(err); }
if (!user) {
return done(null, false, { message: 'no user found' });
}
if(user){
console.log("user's true password is: "+user[0].password);
console.log("password"+psw);
bcrypt.compare(psw, user[0].password, function(err, res) {
if (err){
throw err;}
if(!res) {
console.log('Ooops!. Wrong Pass!');
return done(null, false, req.flash('loginMessage', 'Oops! Wrong password.')); // create the loginMessage and save it to session as flashdata
}
if(res){
response.redirect('dashboard');
}
});
}
});
},
}
how can I send username to the dashboard.html
this is userroute.js
router.get('/dashboard',(req,response)=>{
});
As you are using MEAN stack for your application, what you can do is check login via async call and return user object in response. Then you can store that user into localstorage.
Once user is successful in logIn and you get this "user" object in response, redirect user from login to dashboard using angular redirection not from back-end server.
After redirection use localstorge for getting user information.

User not recognized by Express Passport with my strategy

I have a strange behavior with my Angular - Express + Passport behavior.
On my application, a user is authenticated this way: the AngularJS application calls an external service, linked to NTML, which returns several information such as the email of the current user.
Then, the AngularJS application calls a REST service on my Express backend (/rest/userProfile) to get the full profile of the user. That's when I authenticate the user on the back-end.
However, at the same time, the AngularJS application (during its initialization) calls several others REST api on my back-end (such as retrieving the application configuration in /rest/config, some other stuffs to display on the homepage). These calls are not protected and are generally handled before the call to /rest/userProfile.
In others words, the Express session is created by the first request received on the back-end, which is generally /rest/config and not /rest/userProfile (I think this point is really important).
After all that initialization, the user can call some protected REST api, like /rest/foo/.
But it appears that sometimes, the user is then not recognized on the back-end, despite the fact that the request contains the Express cookie (connect.sid). The logs show that the request object does not contain the passport property.
If I refresh one or two times the browser, everything start to work correctly, i.e. the user is finally recognized. After that, during some times, I can restart my browser and it will work directly without problem.
It seems that if I delay all the requests (like /rest/config) to ensure that /rest/userProfile is the first request received on the server, everything works correctly (i.e. the user will be recognized correctly on protected routes).
Is my understanding correct, in the sense that with my current implementation I have to make the call to /rest/userProfile be the first request received on the backend, so the session created by Passport will contains the user information?
If yes, what I have to change in my implementation (cf. below) to make it work, regardless when the call to /rest/userProfile is received (of course before any protected route)?
If no, what is wrong on my site? Any clue?
The code
On my index.js, I set the following Express middlewares:
app.use(session({
secret: 'xxx',
resave: true,
saveUninitialized: true
}));
app.use(passport.initialize());
app.use(passport.session());
On my main route JS file:
passport.serializeUser(function(user, done) {
console.log('[serialize user]', user);
done(null, user.username);
});
passport.deserializeUser(function(username, done) {
console.log('[deserialize username]', username);
User.findOne({username: username}, function(err, user) {
done(err, user);
});
});
passport.use('ntml-strategy', new LocalStrategy({
usernameField: 'mail',
passwordField: 'password',
passReqToCallback: true
},
function(req, username, password, done) {
console.log('[ntml strategy]', username);
User.findOne({username: username}, function(err, user) {
if (err) {
return done(err);
} else if (user && user !== null) {
return done(null, user);
}
// User does not exist in DB.
// We should create a new user with data received from client.
var newUser = new User({
username: username,
roles: ['user']
});
User.create(newUser, function(err, userSaved) {
if (err) {
return done(err);
}
return done(null, userSaved);
});
});
}));
// The REST api to get user profile
app.post('/rest/userProfile', passport.authenticate('ntml-strategy'), getUserProfile);
function getUserProfile(req, res) {
var user = req.user;
console.log('[getUserProfile]', user);
if (!user) {
return res.status(401).end();
}
res.json({
username: user.username,
roles: user.roles
});
}
// In other file, another route:
app.get('/rest/foo/', isAuthenticated, getUserStuff);
function isAuthenticated(req, res, next) {
if (!req.isAuthenticated()) {
return res.status(401).end();
}
next();
}
function getUserStuff(req, res, next) {
// Do stuff
}
On the User model, I've set the passport-local-mongoose:
User.plugin(passportLocalMongoose, {
usernameField: 'username',
usernameUnique: true
});
Note that removing that plugin does not change anything in the behavior.
Thanks.
For versions: node 5.5, express 4.10.8, passport 0.3.2, passport-local 1.0.0 and Angular 1.5.

Nodejs get user by id

Am using the MEAN stack for an app, i have users that i register and log in using satellizer everything work well.
But when i try to get user by it's id i get nothing, i can do request to get all users but not by id.
Note am using Ionicframework as a forntEnd framework.
Here is the code of my back end end point:
app.get('/api/me', function(req, res) {
User.findById(req.user, function(err, user) {
console.log(req.user);
console.log(user);
res.send(user);
});
})
my Front end code the controller:
.controller('ProfileCtrl', function($scope, $http, $stateParams, $ionicLoading, $timeout, $stateParams) {
$ionicLoading.show({
template: 'Loading...'
});
$http.get('http://localhost:3000/api/me')
.success(function(data) {
console.log("Recived data via HTTP", data);
$timeout(function() {
$ionicLoading.hide();
$scope.user = data;
}, 1000);
})
.error(function() {
console.log("Error while getting the data");
$ionicLoading.hide();
});
})
Request Header:
Accept:application/json, text/plain, */*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:en-US,en;q=0.8,ar;q=0.6,fi;q=0.4,it;q=0.2,en-GB;q=0.2,en-CA;q=0.2
Authorization:Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI1NTAxYjAxMmExMjRlZjIwMTc4M2ExMTQiLCJleHAiOjE0MjcxMzk0NDV9.x9QEdE4E-Vh1SklCheiZqsnJsg8jGzdJnPx2RXeZqS8
Connection:keep-alive
Host:localhost:3000
Origin:http://localhost:8100
Referer:http://localhost:8100/
you missed an important part in your server call, the "ensureAuthenticated":
app.get('/api/me', ensureAuthenticated, function(req, res) {
User.findById(req.user, function(err, user) {
res.send(user);
});
});
the ensureAuthenticate of this satellite example implemenation is a very simple version, it only puts the content of the token.sub into req.user. This is good enough for your query. Typically in a real app one would use passport middleware instead, load the user in the middleware and put it into req.user.
when using the mean stack typically req.user is set to the full user object, i.e. an instance of mongoose document. You want to search by id, so give the query an id:
try
User.findById(req.user._id, function(err, user) {
instead.
But, considering that req.user is already exactly the object that you are querying for, the whole query might just not be needed at all.
If you want to look up a different user than the authenticated one, you need to pass the id you want to query in the URL path, typically something like:
GET /api/users/{id}
then you can get this id using
req.params.id
and pass it to the findById() call

How can I return a database query and redirect at once?

I don't literally need to use "res.redirect()", I just mean I want to take the user to a different page using any workable method.
After the user enters their info, they click a button which calls createUser. createUser successfully adds a new entry to the database. I want the user to also be automatically redirected back to the index page ("/"). I have not found any way to do this. What I have below does hit "app.get('/'), but no redirect happens. Is it possible to put the redirect in app.post('/api/register-new-user')? Can I use window.location somehow within createUser? I have tried both of those ways to no avail.
// CLIENT =====
$scope.createUser = function() {
$http.post('/api/register-new-user', $scope.formData)
.success(function(data) {
$scope.formData = {}; // clear the form so our user is ready to enter another
$scope.users = data;
console.log(data);
// window.location = "./";
})
.error(function(data) {
console.log('Error: ' + data);
});
$http.get('/')
.success(function(data) {
})
.error(function(data) {
console.log('Error: ' + data);
});
};
//SERVER========
app.post('/api/register-new-user', function(req, res) {
bcrypt.genSalt(10, function(err, salt) {
if(err)
res.send(err);
bcrypt.hash(req.body.password, salt, function(err, hash){
if(err)
res.send(err);
User.create({
username : req.body.username,
password : hash
}, function(err, user) {
if(err)
res.send(err)
User.find(function(err, users) {
if(err)
res.send(err);
res.json(users);
});
});
});
});
});
app.get('/register', function(req, res) {
console.log('register');
res.sendfile('./public/views/register.html');
});
OK, so you are doing your browser/server interaction to create a user via AJAX and HTTP redirects over AJAX have no bearing on the URL/page loaded in the browser. So you can forget about server side HTTP redirects. Just send a 201 status to be nicely RESTful and call it good on the server.
On the client, if the POST succeeds you can just trigger a new route with $location.path('/');. Just make sure you declare $location so it gets injected by DI into your controller.
Also note that the active user probably needs to be set on the $rootScope if you want it to be broadly available to the rest of your controllers.
You could try
window.location.href()
Instead of window.location().
This should work with an absolute path.
Although as you are using Angular so it is possible to use the route provider to update the view with out redirecting the user.
Here is some documentation for the route provider.
https://docs.angularjs.org/tutorial/step_07

How to secure feature for authenticated users only in Meanjs when using angularjs

I am working on my first app, and have started with the front-end and angularjs. In general I have found it very intuitive, but the relationship between backend and frontend is where things start to blur for me.
I have now gotten to the point where I want to provide slightly different functionality on some pages depending on whether the user is authenticated or not (in this case the ability to edit some form fields in a form).
From the public angularjs side it seems easy enough to write a basic if statement to provide different functionality to authenticated users (see basic attempt below) but as this is a client side function, how do I prevent a user spoofing authentication to edit things I don't want them to (save to database).
angular.module('core').controller('myCtrl', ['$scope', 'Authentication', 'Menus',
function($scope, Authentication, Menus) {
$scope.authentication = Authentication;
if(typeof $scope.authentication.user == "object"){
// behaviour for authenticated
}else{
// for unauthenticated
}
}
I am new to mean, meanjs and node.js in general, being primarily a php guy, so please be gentle if my question is way off base.
I suggest using passport a npm module for user authentication. Here's some code to get you started. Also take a look at this scotch.io tutorial
// load all the things we need
var LocalStrategy = require('passport-local').Strategy;
// load up the user model
var User = require('../app/models/user');
// expose this function to our app using module.exports
module.exports = function(passport) {
passport.serializeUser(function(user, done) {
done(null, user.id);
});
// used to deserialize the user
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
passport.use('local-signup', new LocalStrategy({
usernameField : 'email',
passwordField : 'password',
passReqToCallback : true // allows us to pass back the entire request to the callback
},
function(req, email, password, done) {
// asynchronous
// User.findOne wont fire unless data is sent back
process.nextTick(function() {
// 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
if (err)
return done(err);
// check to see if theres already a user with that email
if (user) {
return done(null, false, req.flash('signupMessage', 'That email is already taken.'));
} else {
// if there is no user with that email
// create the user
var newUser = new User();
// set the user's local credentials
newUser.local.email = email;
newUser.local.password = newUser.generateHash(password);
// save the user
newUser.save(function(err) {
if (err)
throw err;
return done(null, newUser);
});
}
});
});
}));
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
// 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);
// if the user is found but the password is wrong
if (!user || !user.validPassword(password))
return done(null, false, req.flash('loginMessage', 'Oops! Wrong username or password.')); // create the loginMessage and save it to session as flashdata
// all is well, return successful user
return done(null, user);
});
}));
};

Resources