Express-mysql-session阻止passport deserializeUser运行
我有一个应用程序使用passport.js通过Facebooklogin用户,并试图使用express-mysql-session来保持其login状态。 如果我不包含express-mysql-session代码,那么护照serializeUser和deserializeUser函数就可以正常工作了…但是当我试图用express-mysql-session存储会话的代码时,deserializeUser函数不会不会受到打击,用户永远不会正确login。
server.js文件
var express = require('express'); var mysql = require('mysql'); var passport = require('passport'); var session = require('express-session'); var MySQLStore = require('express-mysql-session')(session); if (typeof process.env.OPENSHIFT_MYSQL_DB_HOST === "undefined"){ var options = { host : 'localhost', port : '3307', user : 'user', password : 'password', database : 'database', socketpath: '/var/run/mysqld/mysqld.sock' } } else { var options = { host : process.env.OPENSHIFT_MYSQL_DB_HOST, port : process.env.OPENSHIFT_MYSQL_DB_PORT, user : process.env.OPENSHIFT_MYSQL_DB_USERNAME, password : process.env.OPENSHIFT_MYSQL_DB_PASSWORD, database : process.env.OPENSHIFT_APP_NAME, socket : process.env.OPENSHIFT_MYSQL_DB_SOCKET } }; var connection = mysql.createConnection(options); var sessionStore = new MySQLStore({ checkExpirationInterval: 900000,// How frequently expired sessions will be cleared; milliseconds. expiration: 86400000,// The maximum age of a valid session; milliseconds. createDatabaseTable: false,// Whether or not to create the sessions database table, if one does not already exist. connectionLimit: 1, schema: { tableName: 'LoginRequests', columnNames: { session_id: 'loginID', expires: 'expires', data:'data' } } }, connection); self.initializeServer = function() { self.app = module.exports = express(); self.app.configure(function() { self.app.set('views', __dirname + '/public'); self.app.set('view engine', 'html'); self.app.engine('html', require('hogan-express')); self.app.enable('view cache'); self.app.use(express.favicon()); self.app.use(express.logger('dev')); self.app.use(express.bodyParser()); self.app.use(express.methodOverride()); self.app.use(express.cookieParser('secret')); self.app.use(session({ key: 'session_cookie_name', secret: 'secret', cookie: {maxAge: 3600000, secure:false}, store: sessionStore, resave: false, saveUninitialized: false })); // required for passport self.app.use(passport.initialize()); self.app.use(passport.session()); // persistent login sessions self.app.use(express.static(path.join(__dirname, 'public'))); self.app.use('/public',express.static(__dirname, '/public')); self.app.use(self.app.router); //self.app.use(require('stylus').middleware(__dirname + '/public')); }); require('./routes/site.js'); require('./config/passport.js')(passport); // pass passport for configuration }
所以,如果我在上面的会话对象中注释掉“store”选项,护照function就会被打中。 如果我离开这条线未评论,deserializeUser函数不会被击中。
护照function
passport.serializeUser(function(user, done) { console.log('you have been serialized!'); done(null, user.id); }); // used to deserialize the user passport.deserializeUser(function(id, done) { console.log('you have been deserialized!'); connection.query("SELECT * FROM Users WHERE id = "+id,function(err,rows){ done(err, rows[0]); }); });
编辑
Mor Pazbuild议我包含一些从debugging模块运行服务器的日志。 以下是用户序列化之前和之后的日志。 用户应该在这附近的某个点反序列化,但从来没有。
GET /auth/facebook 302 81ms - 412b express-mysql-session:log Getting session: oNcJ4UapxCY_zKOyfSBTUWaVhaNZuFRq +356ms you are a user! you have been serialized! express-mysql-session:log Setting session: tgRPY-Mb1VDP2zaSMOFhlf_IWFhVpTia +798ms express-mysql-session:log Getting session: tgRPY-Mb1VDP2zaSMOFhlf_IWFhVpTia +6ms GET /auth/facebook/callback? code=AQCWPvA5ZRMYoTueW6_wWU49Up5ggjW68ufOtiYkU5IzhRjSNyyWnzlQVprgQo_uubQkEVvNI0yo53ET3cWBnDAHUGmAXPBy_ITEmC-biE2KEGEr0iCm_cqjuG90nnePY-k9U2oFUbX2kvLgMeM0kZ-094EHiU_NJjmAJNj6mzTkSE47935RhJy0Tba_sYS88_C0N3kn5f5kcoTC4KsgW1gBHWWJAwZ68Lj94ffVe2hN97580CtzEpJa0wwQHwTBYfmjQ0NfUdx07m4rXW9R7PR06aHDcUDrYqR9Kb0LWq4sZLbQjV5rI7gzkWG-huhq7IY 302 825ms - 72b express-mysql-session:log Setting session: Xo9OjfmJzTFp1CSF6srLi_UyxTCLg-EI +56ms express-mysql-session:log Getting session: Xo9OjfmJzTFp1CSF6srLi_UyxTCLg-EI +23ms express-mysql-session:log Getting session: Xo9OjfmJzTFp1CSF6srLi_UyxTCLg-EI +2ms GET /profile 200 84ms - 4.22kb
不可能复制这个问题,所以我准备了一个实例。 [Github回购]
它是为Openshift而devise的 ,因为我看到了它的环境variables的使用(它可以轻松地适应其他用例)。
我对原始概念做了一些修改:
- replace旧的,不赞成的(快速)捆绑中间件用法。
- 使用类而不是
self = this
概念 - 使用Github而不是Facebook的用户login…
- 包括一些基本的function,以包括新的用户数据库
- 缺less一些原始模块(可以轻松包含)
我希望这可以作为一个起点。
// .: DB Configuration :. const mysql = require('mysql'); var dbconf = {host:process.env.OPENSHIFT_MYSQL_DB_HOST,port:process.env.OPENSHIFT_MYSQL_DB_PORT,user:process.env.OPENSHIFT_MYSQL_DB_USERNAME,password:process.env.OPENSHIFT_MYSQL_DB_PASSWORD,database:process.env.OPENSHIFT_APP_NAME,socket:process.env.OPENSHIFT_MYSQL_DB_SOCKET}} const dbconn = mysql.createConnection(dbconf); /*or create a pool*/ dbconn.connect(); // .: Express & Other Middleware Modules :. var express = require('express'); var path = require('path'); var bodyParser = require('body-parser'); var methodOverride = require('method-override'); var cookieParser = require('cookie-parser'); var serveStatic = require('serve-static'); // .: Sessions :. var passport = require('passport'); var GitHubStrategy = require('passport-github2'); var session = require('express-session'); var MySQLStore = require('express-mysql-session')(session); var sessionStoreConf = { connectionLimit:1,checkExpirationInterval:900000,expiration:86400000, createDatabaseTable:true,schema:{tableName:'LoginRequests',columnNames:{session_id:'loginID',expires:'expires',data:'data'}} }; var sessionStore = new MySQLStore(sessionStoreConf,dbconn); // .: Server (class) :. class Server { constructor(port, ip){ this.app = express(); this.app.use(cookieParser('secret')); this.app.use(session({ key:'session_cookie_name', secret:'secret', cookie:{maxAge:3600000,secure:false}, store: sessionStore, resave:false, saveUninitialized:false })); this.app.use(passport.initialize()); this.app.use(passport.session()); this.app.use(serveStatic(path.join(__dirname,'public'))) this.app.listen(port,ip,function(){console.log('[i] Application worker started.');}); //require('./routes/site.js'); //~Example (routes/site.js) : this.app.get("/",function(req,res){res.send("<a href='./auth/github'>Click here to login (GitHub)</a>");}) this.app.get('/auth/github',passport.authenticate('github',{scope:['user:email']})); this.app.get('/auth/github/callback',passport.authenticate('github',{failureRedirect:'/'}),function(req,res){res.redirect('/success');}); // route for valid logins this.app.get('/success', function(req, res){ if(req.user){ console.log(req.user); res.send(req.user); } else{ res.redirect('/login'); } }); // route to check the sessionStore table entries in the browser this.app.get('/sessions',function(req,res){ dbconn.query("SELECT * FROM LoginRequests",function(err,rows){ if(err){console.log(err);}else{ if(rows.length!=0){ res.send(JSON.stringify(rows)); console.log(rows); }else{res.send("No LoginRequests found");} } }); }); //require('./config/passport.js')(passport); //~Example (config/passport.js) : passport.use(new GitHubStrategy( {clientID:"clientID",clientSecret:"clientSecret",callbackURL:"callbackURL"}, function(token, tokenSecret, user, cb){CheckUser('github',user,cb);} )); } } const server = new Server(process.env.OPENSHIFT_NODEJS_PORT,process.env.OPENSHIFT_NODEJS_IP); // .: Passport : Serialize & Deserialize User :. passport.serializeUser(function(user, done){ console.log('[passport] serializeUser'); done(null,user.id); }); passport.deserializeUser(function(id, done) { console.log('[passport] deserializeUser'); dbconn.query("SELECT * FROM Users WHERE id=?",[id],function(err,rows){ if(err){console.log(err);}else{ if(rows.length!=0){ done(err,rows[0]); } else{ done(err,null); } } }); }); //:Check if user exists: function CheckUser(platform,user,cb){ dbconn.query("SELECT * FROM Users WHERE id=?",[user.id],function(err,rows){ if(err){console.log(err); cb(err,null);}else{ if(rows.length!=0){cb(null,user);} else{CreateUser(platform,user,cb);} } }); } //:Create new user: function CreateUser(platform,user,cb){ switch(platform){ case "github": var newUserObj = {id:user.id,platform:platform,email:user.emails[0].value}; dbconn.query("INSERT INTO Users SET ?",newUserObj,function(err){ if(err){console.log(err); cb(err,null);}else{cb(null,user);} }); break; default: console.log("[error] (createUser) : platform not implemented :",platform); cb(err,null); break; } }