diegoaguilar
diegoaguilar

Reputation: 8376

How can I manage sessions with Passport JS for some routes using express?

I got below express node.js server code using Passport. At it my whole routes definition depends upon a MongoDB connection using mongo-db but model used by Passport is done through another connection by mongoose. I mention these two details cause I think it should also be coded in a better way.

However, the main problem is that even though Passport it's doing it's work, I still can go to localhost/registro directly no matter I didn't logged in first.

When someone tried to access to localhost/registro it should be redirected to start page if a login and authentication wasn't done first.

I care about a safe implementation of it, I'd also like to have some information about the user during the session time.

I'm quite confused about what I should try, cookies, sessions, etc. Apart that in new express version middlewares work different than before.

This is my server.js:

var express =       require('express')
var mongodb =       require('mongodb')
var mongoose =      require('mongoose')
var bodyParser =    require('body-parser')
var passport =      require('passport')
var LocalStrategy = require('passport-local').Strategy;

var app = express()

var BSON = mongodb.BSONPure

app.use(passport.initialize());
app.use(passport.session());

app.use(express.static(__dirname+"/public"))
app.use(bodyParser())

var MongoDBClient = mongodb.MongoClient

mongoose.connect('mongodb://localhost/psicologosTuxtepecDB')

var Schema = mongoose.Schema
var userCredential = new Schema({

    username:   String,
    password:   String

},  {
    collection:     'members'
})

var userCredentials = mongoose.model('members', userCredential)

passport.serializeUser(function(user, done) {
  done(null, user);
})

passport.deserializeUser(function(user, done) {
  done(null, user);
})

passport.use(new LocalStrategy(function(username, password, done) {
  process.nextTick(function() {
    userCredentials.findOne({
      'username': username, 
    }, function(err, user) {
      if (err) {
        return done(err);
      }

      if (!user) {
        return done(null, false);
      }

      if (user.password != password) {
        return done(null, false);
      }

      return done(null, user);
    });
  });
}));

MongoDBClient.connect("mongodb://localhost/psicologosTuxtepecDB", function (error, psicologosTuxtepecDB) {

    if (error) {

        console.log("We've got a connection error, so far we should take this function better for a correct debug")
    }

    else {

        console.log("Connection to psicologosTuxtepecDB has been successful")

        // Seleccionamos una colección
        var psicologosCollection = psicologosTuxtepecDB.collection("psicologos")

        app.get('/registro', function(request,response) {

            response.sendfile("public/html/registro.html")
        })

        // Cuando nos hagan una petición HTTP de tipo POST en la ruta psicologos...
        app.post("/psychos", function(request, response) {

            var psychologist = {

                personalData:           request.body._personalData,
                professionalData:       request.body._professionalData,
                professionalInterests:  request.body._professionalInterests
            }


            psicologosCollection.insert(psychologist, function(error, responseFromDB) {

                if (error) {response.send(responseFromDB)}

                console.log("Se ha insertado: "+ JSON.strinfigy(responseFromDB))
                response.send(responseFromDB)
            })
        })

        app.get("/psychos/:id", function(request, response) {

            var id = new BSON.ObjectID(peticion.params.id)

            psicologosCollection.findOne( 
                                            {'_id':id},
                                            function(error,responseFromDB) { if (error) {response.send(responseFromDB)} response.send(responseFromDB)}
                                        )
        })

        app.get("/psychos", function(request,response) {

            psicologosCollection.find().toArray(function(error,responseFromDB) {
                if (error) {response.send(responseFromDB)}
                response.send(responseFromDB)
            })
        })

        app.post('/login',
          passport.authenticate('local', {
            successRedirect: '/loginSuccess',
            failureRedirect: '/loginFailure'
          })
        )

        app.get('/loginFailure', function(req, res, next) {
            res.redirect('/')
        })

        app.get('registro', function(request, response) {
            response.sendfile('public/html/registro.html')
        })

        app.get('/loginSuccess', function(req, res, next) {
          res.redirect('/registro')

    })      

    app.listen(80, function () {
        console.log("app escuchando en el puerto Maricela fecha de nacimiento DDMM")
    })
}

})

These are my Passport statements:

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

passport.deserializeUser(function(user, done) {
  done(null, user);
})

passport.use(new LocalStrategy(function(username, password, done) {
  process.nextTick(function() {
    userCredentials.findOne({
      'username': username, 
    }, function(err, user) {
      if (err) {
        return done(err);
      }

      if (!user) {
        return done(null, false);
      }

      if (user.password != password) {
        return done(null, false);
      }

      return done(null, user);
    });
  });
}));

Upvotes: 0

Views: 2626

Answers (1)

Josh C.
Josh C.

Reputation: 4373

Express "chains" route methods. The basic idea behind securing routes in Express.js is to have a method that checks the a&a before allowing the request to proceed to the intended route. There are a few ways to do this:

Method 1: Add the auth method to the route declaration

function requireAuth(req,res,next){
   if user is authenticated
      next();
   else
      res.send(401);
}

app.get('/registro', requireAuth, function(request, response) {
            response.sendfile('public/html/registro.html')
        })

Method 2: Declare a route handler for your auth

app.get('/registro', function(req,res,next){
       if user is authenticated
          next();
       else
          res.send(401);
})

app.get('/registro', function(request, response) {
                response.sendfile('public/html/registro.html')
            })

Method 3: Use app.use() instead of a verb

With this method, you need to consider when app.router gets inserted into the middle-ware.

Edit 1: Where would the require auth method be declared If you plan on placing route handlers in multiple .js files, it's a good idea to put your require auth mehtod in a separate .js file as well and require it where appropriate.

Otherwise, you can just stick it in the same file with everything else.

Edit 2: How do sessions work in Express.js and Passport.js

From the Passport.js documentation, you first need to configure the express session before the passport session:

app.use(express.session({ secret: 'keyboard cat' }));  
app.use(passport.initialize());   
app.use(passport.session());

Note: You should probably consider using something other than the memory store for session management.

Along with the serializeUser and deserializeUser methods, at this point Passport will have placed a .user on the request.

You can also use req.isAuthenticated() to determine if the user is authenticated.

Note 2: I've had problems getting the serializeUser and deserializeUser methods to work with Passport-Saml. If that is the case, just manage the session yourself.

Upvotes: 2

Related Questions