2014-03-05 65 views
7

我創建了一個帶護照的簡單身份驗證應用程序(請參閱下面的代碼)。通過會話中間件進行表達,爲請求客戶端沒有會話的每個請求創建一個會話。我想只在登錄後分配會話或創建新會話後分配會話。使用Passport進行身份驗證後創建新會話

這是因爲我最終會做了HTTPS登錄,並想阻止黑客從已通過驗證的用戶劫持會話。

這裏是我的服務器代碼:

// Server.js configures the application and sets up the webserver 

//importing our modules 
var express = require('express'); 
var app = express(); 
var port = process.env.PORT || 8080; 
var mongoose = require('mongoose'); 
var passport = require('passport'); 
var flash = require('connect-flash'); 
var MongoStore = require('connect-mongo')(express); 

var configDB = require('./config/database.js'); 

//Configuration of Databse and App 

mongoose.connect(configDB.url); //connect to our database 

require('./config/passport')(passport); //pass passport for configuration 

app.configure(function() { 

    //set up our express application 

    app.use(express.logger('dev')); //log every request to the console 
    app.use(express.cookieParser()); //read cookies (needed for auth) 
    app.use(express.bodyParser()); //get info from html forms 
    app.set('view engine', 'ejs'); //set up ejs for templating 

    //configuration for passport 
    app.use(express.session({ secret: 'olhosvermdfgytuelhoseasenhaclassica', 
     cookie: { 
      maxAge: 120000 }, 
     store: 
      new MongoStore({ 
       db: 'xYrotr4h', 
       host: 'novus.modulusmongo.net', 
       port: 27017, 
       username: 'gdog', 
       password: 'fakepassowrd123' 
      }) 
     })); //session secret + expiration + store 
    app.use(passport.initialize()); 
    app.use(passport.session()); //persistent login session 
    app.use(flash()); //use connect-flash for flash messages stored in session 

}); 

//Set up routes 
require('./app/routes.js')(app, passport); 

//launch 
app.listen(port); 
console.log("Server listening on port" + port); 

在我的新護照的本地策略,我試圖用req.session.regenerate()或req.session.reload()當用戶成功驗證反對數據庫但導致服務器崩潰。

這是我如何定義我的策略:

//Passport.js sets up our local strategies 

//imports 

var LocalStrategy = require('passport-local').Strategy; 
var User = require('../app/models/user'); 

//export this as a module since we give it to passport 

module.exports = function(passport) { 
    //Set up the session for persistent login 

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

    //used to serialize the user 
    passport.deserializeUser(function(id, done) { 
     User.findById(id, function(err, user) { 
      done(err, user); 
     }); 
    }); 

    //setting up local sign up 

    passport.use('local-signup', new LocalStrategy({ 
      //by default, the local strategy uses usernames and password, we will override with email 
      usernameField: 'email', 
      passwordField: 'password', 
      passReqToCallback: true 
     }, 
     function(req, email, password, done) { 
      console.log("Callback ran!"); 
      //asynchronous 
      //User.findOne wont fire unless data is sent back 
      process.nextTick(function() { 
       console.log("I did run!"); 
       //find user whose email is the same as form email 
       // we are checking to see if the user trying to sign up already exists 
       User.findOne({ 'local.email': email }, function(err, user) { 
        //if there any errors, return the errors 
        if (err) { 
         return done(err); 
        } 
        //check to see if there any users already with that email 
        if (user) { 
         return done(null, false, req.flash('signupMessage', 'That email is already taken.')); 
        } else { 
         console.log('New user will be added to the DB!'); 
         //if there is no user with that e-mail, create the user 
         var newUser = new User(); 

         //we set the user's local credentials 
         newUser.local.email = email; 
         newUser.local.password = newUser.generateHash(password); 

         //save the user in the store 
         newUser.save(function(err) { 
          if (err) { 
           throw err; 
          } 
          return done(null, newUser); 
         }); 
        } 
       }); 
      }); 
     })); 

     // ========================================================================= 
    // LOCAL LOGIN ============================================================= 
    // ========================================================================= 
    // we are using named strategies since we have one for login and one for signup 
    // by default, if there was no name, it would just be called 'local' 

    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 no user is found, return the message 
      if (!user) 
       return done(null, false, req.flash('loginMessage', 'No user found.')); // 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)) 
       return done(null, false, req.flash('loginMessage', 'Oops! Wrong password.')); // create the loginMessage and save it to session as flashdata 

      // all is well, return successful user 
      // removing the req.session.regenerate fixes any crashing 
      req.session.regenerate(function(err, done, user){ 
        return done(null, user); 
       }); 

     }); 

    })); 

}; 
+0

如果黑客可以從用戶劫持會話,他們就不能劫持所生成的新會話? – bnuhero

+1

我相信他們至少很難區分經過身份驗證和未經身份驗證的會話。經過身份驗證的會話將通過HTTPS進行。 –

回答

-1

我認爲你需要更換:

req.session.regenerate(function(err, done, user){ 
    return done(null, user); 
}); 

有:

req.login(user, function(err) { 
    if (err) return res.status(500).send('error'); 
    return done(null,user); 
    }); 

req.login內部調用您的passport.serializeUser()功能。

14

挖掘到護照和快遞會議圖書館後,我已經想通了!

var session = function (req, res) { 
    var temp = req.session.passport; // {user: 1} 
    req.session.regenerate(function(err){ 
     //req.session.passport is now undefined 
     req.session.passport = temp; 
     req.session.save(function(err){ 
      res.send(200); 
     }); 
    }); 
}; 

app.post('/login', passport.authenticate('local'), session); 

基本上我讓護照先做了驗證,即它重視的對象到req.session.passport。 Passport使用此對象來查找來自session - > userId的進一步請求的映射。當您重新生成會話時,req.session.passport對象會丟失。因此,您必須確保將其轉移到新生成的會話並保存。

+1

太棒了,謝謝!這應該是答案...我在這個問題上掙扎如此之多,以至於我覺得自己寫了'passport.js' :-) –

+0

這真的應該是被接受的答案;這是確切的潛在需求。 – delfuego

0

看起來Jared不想直接支持這個,我不確定我是否同意issue #194 - 至少護照應該暴露自己的會話重新生成函數。在任何情況下,您可以通過更換一般解決這個問題:

req.session.regenerate(function(err, done, user){ 
    return done(null, user); 
}); 

像這樣的東西:

var passport = req._passport.instance; 
req.session.regenerate(function(err, done, user) { 
    req.session[passport._key] = {}; 
    req._passport.instance = passport; 
    req._passport.session = req.session[passport._key]; 
    return done(null, user); 
}); 
相關問題