Angela Angela - 1 month ago 11
Node.js Question

PassportJS authentication

So, I have everything working but it is not showing it is an authenticate user even though it arrives at the proper places...

javascript code from the page to validate login

var UserManager = {
validateLogin : function (username, password) {
var userData = {
username: username,
password: password
}
return new Promise(function(resolve, reject) {
$.ajax({
url: "/musicplayer/users/api/login",
dataType: "json",
data: userData,
type: "POST",
success: function loginSuccess(result, status, xhr) {
resolve(null);
},
error: function loginError(xhr, status, result) {
reject(new Error(result));
},
});
});
}


}

function userLogin(){
UserManager.validateLogin($('#loginEmail').val(), $('#loginPassword').val()).then(function(response) {
window.location = '/musicplayer/library'
},
function(error){
$("#msgBox").messageBox({"messages" : error.message, "title" : "Warning", boxtype: 4 });
$("#msgBox").messageBox("show");
});
return false;
}


local.strategy.js

var passport = require('passport');
var localStrategy = require('passport-local').Strategy;
var userLibrary = require('../../classes/music/userlibrary.js');

module.exports = function () {
passport.use(new localStrategy(
{
usernameField: 'username',
passwordField: 'password'
},
function(username, password, done) {
//validating user here
var userManager = new userLibrary.UserManager();
userManager.login(username, password).then(
function (user){
done(null, user);
},
function (reason){
if (reason.err) {
done(err, false, info);
}
else {
done(null, false, {message: reason.message});
}
}
);
})
);
};


Router

/******* validate the user login ********/
usersRouter.post('/api/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) {
console.log("Login Failed", err.message + " - " + err.stack);
if (req.xhr){
res.status(500).send({ error: 'Internal Error' });
}
else {
next(err);
}
}
else if (!err && !user){
err = new Error();
err.message = info.message;
err.status = 401;
console.log("Invalid Data", err.message);
if (req.xhr){
res.status(401).send({ error: err.message });
}
else {
next(err);
}
}
else if (user){
console.log("Successful Login:", user);
res.status(200).send({message: "successful"});
}
}
)(req, res, next);
});


passport.js file which has my Middleware...

var passport = require("passport");

module.exports = function (app) {
app.use(passport.initialize());
app.use(passport.session());
passport.serializeUser(function(user, done){
done(null, user);
});
passport.deserializeUser(function(user, done){
done(null, user);
});

require('./strategies/local.strategy')();

app.all('/musicplayer/*', function (req, res, next){
// logged in
//need function for exceptions
if (req.user || req.url === '/musicplayer/users/api/login' || req.url === '/musicplayer/users/signin') {
next();
}
// not logged in
else {
// 401 Not Authorized
var err = new Error("Not Authorized");
err.status = 401;
next(err);
}
});
}


Userlibrary/UserManager
I am using promises to be able to utilize the creation of a library and to deal with sync versus async issues that I ran into early on...

var sqlite3 = require('sqlite3').verbose();

function User() {
this.email = "";
this.password = "";
this.userid = "";
};

function UserManager () {
this.user = new User();
};

UserManager.prototype.login = function (email, password) {
var db = new sqlite3.Database('./data/MusicPlayer.db');
params = {
$email: email,
$password: password
}
var self = this;
return new Promise(function(resolve, reject){
db.serialize(function () {
db.get("SELECT * FROM users WHERE email = $email and password = $password", params, function (err, row) {
db.close();
if (!err && row) {
//log in passed
self.user.userid = row.userid;
self.user.email = row.email;
self.user.password = row.password;
resolve(self.user);
}
else if (!err) {
//log in failed log event
reject({
err: err,
message: null
});
}
else {
//error happened through out an event to log the error
reject({
message : "Email and/or Password combination was not found",
err : null
});
}
});
});
});

};

module.exports = {
User : User,
UserManager : UserManager
}


Now, I have debugged this and it is for sure getting to "successful Login"

Returns to the browser with success, the browser says okay let me redirect you to the library page (which is really just a blank page). When it goes to my library page I get a 401 unauthorized.

So if I debug inside the middleware to ensure authentication. I look at req.user and it is undefined and I try req.isAuthenticated() it returns a false.

I think I must be missing something...

What I want is a global authentication saying hey is this person logged in. And then I will set up the route/route basis say okay do they have permission for this page or web service call.

Right now I am sticking with session for everything as it is not useful to me to learn web tokens at this point and time.

Any help would be appreciated... I been around and around on this looking at examples out there. But the examples I find are the "basic" examples no one calling a library to validate from database or they are not trying to set up the authorization globally but rather on a route by route basis.

Answer

Upon searching I found this article

https://github.com/jaredhanson/passport/issues/255

then I found this in documentation

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('/users/' + user.username);
        });
      })(req, res, next);
});

and that worked for me... I basically forgot to do the req.logIn method itself when using the custom callback.... I knew it was something simple... Hope this helps someone in the future.