javascript - Express-mysql-session evitando que se ejecute el pasaporte deserializeUser
node.js passport.js (1)
Tengo una aplicación que usa passport.js para iniciar sesión en los usuarios a través de Facebook, y estoy tratando de usar express-mysql-session para mantener sus estados de inicio de sesión. Si no incluyo el código express-mysql-session, las funciones de pasaporte serializeUser y deserializeUser funcionan bien ... sin embargo, cuando descomento el código que intenta almacenar su sesión con express-mysql-session, la función deserializeUser no funciona no te golpeen, y el usuario nunca inicia sesión correctamente.
archivo 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
}
Entonces, si comento la opción "almacenar" en el objeto de sesión anterior, las funciones del pasaporte se ven afectadas. Si dejo esta línea sin comentarios, la función deserializeUser no se ve afectada.
Funciones de pasaporte
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]);
});
});
EDITAR
Mor Paz sugirió que incluyera algunos de los registros de cuando ejecuto mi servidor con el módulo de depuración. A continuación se muestran los registros justo antes e inmediatamente después de que el usuario se serialice. El usuario debe ser deserializado en algún momento cerca de esto, pero nunca lo es.
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
Era imposible replicar el problema, así que preparé un ejemplo de trabajo. [Repositorio de Github]
Está diseñado para Openshift , ya que vi el uso de sus variables de entorno (se puede adaptar con facilidad para otros casos de uso).
Hice algunas modificaciones al concepto original:
- Reemplazó los viejos usos de middleware en desuso (obsoletos).
-
Usar una
clase en
lugar del
self = this
concepto - Usando Github en lugar de Facebook para el inicio de sesión del usuario ...
- Incluye algunas funciones básicas para incluir nuevos usuarios a la base de datos
- Faltan algunos módulos originales (se pueden incluir con facilidad)
Espero que pueda ser útil como punto de partida.
// .: 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;
}
}