I am fairly new to node and I am trying to create a simple login/signup system with passportjs. I have my passport configuration file in which i pass the passport object as a parameter as you can see below.
My passport configuration file:
var LocalStrategy = require('passport-local').Strategy;
var User = require('./../models/user');
var mysql = require('./../database/mysql_setup');
var mysqlPool = mysql.pool;
// expose this function to our app using module.exports
module.exports = function(passport) {
mysqlPool.getConnection(function(error, connection) {
if (error) throw error;
connection.query('USE vidyawxx_build2');
// =========================================================================
// passport session setup ==================================================
// =========================================================================
// required for persistent login sessions
// passport needs ability to serialize and deserialize users out of session
// used to serialize the user for the session
passport.serializeUser(function(user, done) {
done(null, user.username);
});
// used to deserialize the user
passport.deserializeUser(function(username, done) {
connection.query("SELECT * FROM `"+mysql.dbSpecs.prefix+"users` WHERE username = " + connection.escape(username), function(err,rows){
done(err, rows[0]);
});
});
// =========================================================================
// LOCAL SIGNUP ============================================================
// =========================================================================
// 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-signup', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField : 'username',
passwordField : 'password',
passReqToCallback : true // allows us to pass back the entire request to the callback
},
function(req, username, password, done) {
// find a user whose username is the same as the forms username
// we are checking to see if the user trying to login already exists
connection.query("SELECT * FROM `"+mysql.dbSpecs.prefix+"users` WHERE `username` = "+connection.escape(username),function(err,rows){
if (err)
return done(err);
if (rows.length) {
return done(null, false, req.flash('error', 'This username is already in use.'));
} else {
// if there is no user with that username
// create the user
var newUserMysql = new User(username, password);
newUserMysql.generateHash(function(error, hash) {
if(error) {
return done(error);
}
var insertQuery = "INSERT INTO `"+mysql.dbSpecs.prefix+"users` ( username, password ) values (" + connection.escape(newUserMysql.username) +",'"+ hash +"')";
connection.query(insertQuery,function(err,rows){
if(err) {
return done(error);
}
return done(null, rows);
});
});
}
});
}
));
// =========================================================================
// 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
usernameField : 'username',
passwordField : 'password',
passReqToCallback : true // allows us to pass back the entire request to the callback
},
function(req, username, password, done) { // callback with email and password from our form
connection.query("SELECT * FROM `"+mysql.dbSpecs.prefix+"users` WHERE `username` = " + connection.escape(username), function(err,rows){
if (err) {
return done(err);
}
if (rows.length === 0) {
return done(null, false, req.flash('error', 'Oops! Wrong username or password.')); // req.flash is the way to set flashdata using connect-flash
}
// if the user is found but the password is wrong
var newUser = new User(username, password);
newUser.compareHash(function(error, result) {
if(result) {
return done(null, rows[0]);
} else {
return done(null, false, req.flash('error', 'Oops! Wrong username or password.')); // create the loginMessage and save it to session as flashdata
}
});
});
}
));
connection.release();
});
};
My problem lies in the fact that if my mysql server is down for any reason, the error is thrown in my first line. I want to be able to redirect my users to a simple page that gives him a message like "Something is wrong with the database, please try later". The thing is, when i throw the error, my app just shuts down giving any visitor the ERR_CONNECTION_REFUSED response.( I am currently working this locally.
This is my app.js file:
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var passport = require('passport');
var passportConfig = require('./config/passport');
var session = require("express-session");
var flash = require("connect-flash");
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var app = express();
app.use(express.static(path.join(__dirname, 'public')));
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
passportConfig(passport);
app.use(session({
secret: "aPa1fgOed(&fjkKLN34%#$lpv@@",
resave: true,
saveUninitialized: true,
cookie: { maxAge: 1000*60*15 } //15 minutes in milliseconds
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
//create local vaariables for all our templates to use
app.use(function(req, res, next) {
res.locals.errors = req.flash("error");
res.locals.infos = req.flash("info");
res.locals.successes = req.flash("success");
next();
});
app.use('/', indexRouter);
app.use('/users', usersRouter);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
That being said, since the error is thrown in my passport-config file, which doesnt follow the middleware convention of having a req, res and next params, how can i redirect my users to a page like the one mentioned above gracefully ?
Just to be sure, I will say this again, this concerns only mysql connection errors. I know that i can return other errors through my passport-config methods by using done(), but database connection errors occur outside the functions with a done param.
Thanks in advance
Looks like after some digging around the only workaround I could think of is incorporating the queries inside the passport configuration methods so that I could pass back any database connection error through the done() function;
This is my modified passport config file
// load all the things we need
var LocalStrategy = require('passport-local').Strategy;
var User = require('./../models/user');
var mysql = require('./../database/mysql_setup');
var mysqlPool = mysql.pool;
// expose this function to our app using module.exports
module.exports = function(passport) {
//connection.query('USE vidyawxx_build2');
// =========================================================================
// passport session setup ==================================================
// =========================================================================
// required for persistent login sessions
// passport needs ability to serialize and deserialize users out of session
// used to serialize the user for the session
passport.serializeUser(function(user, done) {
done(null, user.username);
});
// used to deserialize the user
passport.deserializeUser(function(username, done) {
mysqlPool.getConnection(function(dbError, connection) {
if(dbError) {
return done(dbError);
}
connection.query("SELECT * FROM `"+mysql.dbSpecs.prefix+"users` WHERE username = " + connection.escape(username), function(err,rows){
if(err) {
done(err);
connection.release();
return;
}
connection.release();
done(err, rows[0]);
});
});
});
// =========================================================================
// LOCAL SIGNUP ============================================================
// =========================================================================
// 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-signup', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField : 'username',
passwordField : 'password',
passReqToCallback : true // allows us to pass back the entire request to the callback
},
function(req, username, password, done) {
// find a user whose username is the same as the forms username
// we are checking to see if the user trying to login already exists
mysqlPool.getConnection(function(dbError, connection) {
if(dbError) {
return done(dbError);
}
connection.query("SELECT * FROM `"+mysql.dbSpecs.prefix+"users` WHERE `username` = "+connection.escape(username),function(err,rows){
if (err) {
connection.release();
return done(err);
}
if (rows.length) {
connection.release();
return done(null, false, req.flash('error', 'This username is already in use.'));
} else {
// if there is no user with that username
// create the user
var newUserMysql = new User(username, password);
newUserMysql.generateHash(function(error, hash) {
if(error) {
connection.release();
return done(error);
}
var insertQuery = "INSERT INTO `"+mysql.dbSpecs.prefix+"users` ( username, password ) values (" + connection.escape(newUserMysql.username) +",'"+ hash +"')";
mysqlPool.query(insertQuery,function(err,rows){
if(err) {
connection.release();
return done(error);
}
connection.release();
return done(null, rows);
});
});
}
connection.release();
});
});
}
));
// =========================================================================
// 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
usernameField : 'username',
passwordField : 'password',
passReqToCallback : true // allows us to pass back the entire request to the callback
},
function(req, username, password, done) { // callback with email and password from our form
mysqlPool.getConnection(function(dbError, connection) {
if(dbError) {
return done(dbError);
}
connection.query("SELECT * FROM `"+mysql.dbSpecs.prefix+"users` WHERE `username` = " + connection.escape(username), function(err,rows){
if (err) {
connection.release();
return done(err);
}
if (rows.length === 0) {
connection.release();
return done(null, false, req.flash('error', 'Oops! Wrong username or password.')); // req.flash is the way to set flashdata using connect-flash
}
// if the user is found but the password is wrong
var newUser = new User(username, password);
newUser.compareHash(function(error, result) {
if(result) {
connection.release();
return done(null, rows[0]);
} else {
connection.release();
return done(null, false, req.flash('error', 'Oops! Wrong username or password.')); // create the loginMessage and save it to session as flashdata
}
});
});
});
}
));
};
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.