Persistent sessions with connect-session-sequelize - node.js

I am making a website with a login system and I would like the users to be able to stay logged in even after the browser has been closed. Only destroy the session when the user logs out. I have searched online for the solution and came across with the suggestion to use connect-session-sequelize . I read the documentation and put my best effort to make the code work but my lack of experience in this gets in a way.
Problem:
My code does not give me the result of keeping a user logged in after the server restart. My code is:
var express = require('express');
var app = express();
var cookieParser = require('cookie-parser');
var session = require('express-session');
var SequelizeStore = require('connect-session-sequelize')(session.Store);
var pug = require('pug');
var bodyParser = require('body-parser');
var bcrypt = require('bcrypt');
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(express.static('public'));
app.use(cookieParser());
app.set('views', './views');
app.set('view engine', 'pug');
var Sequelize = require('sequelize');
var db = new Sequelize('postgres://'+ process.env.POSTGRES_USER + ':' +
process.env.POSTGRES_PASSWORD + '#localhost/terranova', {
host: 'localhost',
dialect: 'postgres',
storage: './session.postgres',
define: {
timestamps: true
}
});
var sessionStore = new SequelizeStore({
db: db,
checkExpirationInterval: 15 * 60 * 1000,
expiration: 24 * 60 * 60 * 60 * 1000
});
app.use(session({
secret: 'salajhgdusdajss',
store: sessionStore,
resave: false,
saveUninitialized: false,
proxy: true
}));
sessionStore.sync()
var Session = db.define('Session', {
sid: {
type: Sequelize.STRING,
primaryKey: true
},
userId: Sequelize.STRING,
expires: Sequelize.DATE,
data: Sequelize.STRING(50000)
});
var User = db.define('user', {
username: Sequelize.STRING,
password: Sequelize.STRING,
});
function extendDefaultFields(defaults, session) {
return {
data: defaults.data,
expires: defaults.expires,
userId: session.userId
};
}
var store = new SequelizeStore({
db: db,
table: 'Session',
extendDefaultFields: extendDefaultFields
});
Subproblems:
The documentation indicates to add 'var store = new SessionStore' instead of 'var store = new SequelizeStore' but it gives me an error: 'SessionStore is not defined'. Not sure if I'm doing something wrong?
I can see inside 'users' table, but for some reason, I cannot look inside the table of 'Sessions', with 'select * from Sessions;' I get the response of 'relation "sessions" does not exist'. Why is this so?
expiration: 24 * 60 * 60 * 1000 --> default expiry of 24 hours. Does this indicate the time of the session? If yes, what would be the maximum possible time (in case unlimited is impossible)?
Could someone please explain me what do I need to do/add/remove from my code to be able to achieve my goal?
For more info, here is the login page...
app.get('/login', function(req,res) {
res.render('login')
})
app.post('/login', function(req,res) {
var username = req.body.username
var password = req.body.password
User.findOne({
where: {
username: username
}
}).then(function(user) {
if(username.length === 0 || password.length === 0) {
res.render('login', {
message: "Username or password missing"
});
return;
};
if(user == null) {
res.render('login', {
message: "User not in the system, please register"
});
return;
} else {
var hash = user.password
bcrypt.compare(password, hash, function(err, result) {
if (err) {
res.render('login', {
message: 'Invalid email or password, please try again or register'
})
};
if(result === true) {
req.session.user = user;
res.redirect('/home');
}
else {
res.render('login', {
message: "Something went wrong, please try again"
});
};
});
};
});
})
...and here is the home page.
app.get('/home', function(req,res) {
var user = req.session.user
if (user === undefined) {
res.render('login', {
message: 'Please log in to have the access'
});
} else {
res.render('home', {
user: user
});
}
})
Big thanks in advance for helping me!

Related

How to prevent myself from being constantly logged out from Heroku? (possibly express session problem)

I have a website project with frontend at Netlify and backend at Heroku. Currently, I use express session for recording login information. Just now, with about 40 users logging into the website at the same time, I started to be logged out by Heroku much more frequently and have the error message "Application error" displayed at my server site, like this.
I wonder if the phenomenon is caused by the large number of session information stored in my server after all the users log in at once (since I use express session), but honestly, I don't know how to transform from express to cookie session.
Also, I'm aware that there are quotas for the number of queries sent to the database, in this case ClearDB (MySQL) under Heroku, yet I am not banned from reconnecting with the server after logging in again to Heroku, so it may not be the problem.
How can I fix it? Thanks in advance!
This is my code in index.js (with some unrelated methods left out) in my website's server folder:
const express = require('express')
const mysql = require('mysql')
const cors = require('cors')
const session = require('express-session')
const bodyParser = require('body-parser')
const cookieParser = require('cookie-parser')
const mysqlStore = require('express-mysql-session')(session);
const port = 3010
const app = express()
app.use(express.json())
app.use(cors({
origin: ["https://xxx.netlify.app"],
methods: ["GET", "POST"],
credentials: true
}))
const options = {
host: "xxx.cleardb.net",
port: 3306,
user: "xxx",
password: "xxx",
database: "heroku_xxx",
createDatabaseTable: true,
schema: {
tableName: 'session_tab',
columnNames: {
session_id: 'session_id',
expires: 'expires',
data: 'data'
}
}
}
const sessionStore = new mysqlStore(options);
app.use(cookieParser())
app.use(bodyParser.urlencoded({extended: true}))
app.set('trust proxy', 1)
app.use(session({
key: "userId",
secret: "nosecret",
store: sessionStore,
resave: true,
saveUninitialized: false,
cookie: {
sameSite: "none",
secure: true,
httpOnly: true,
maxAge: 600 * 1000
}
}))
app.use((req, res, next) => {
res.setHeader("Access-Control-Allow-Origin", "https://xxx.netlify.app");
res.setHeader(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept"
);
res.setHeader(
"Access-Control-Allow-Methods",
"GET, POST, PATCH, DELETE, OPTIONS"
);
res.setHeader('content-type', 'application/json');
next();
});
const db = mysql.createPool({
// create an instance of the connection to the mysql database
host: 'xxx.cleardb.net', // specify host name
user: 'xxx', // specify user name
password: 'xxx', // specify password
database: 'heroku_xxx', // specify database name
})
...
app.post('/login', (req, res) => {
const username = req.body.username
const password = req.body.password
console.log("username");
console.log(username);
console.log("password");
console.log(password);
db.query(
'SELECT * FROM user where username = ? AND password = ?',
[username, password],
(err, result) => {
console.log("result");
console.log(result);
if (err) {
res.send({ err: err })
}
if (result.length) {
req.session.user = result;
console.log("req.session.user (post /login)");
console.log(req.session.user);
if(result[0].role == "student") {
let name = result[0].lastname + result[0].firstname;
console.log(name);
req.session.userfullname = name;
console.log("req.session.userfullname");
console.log(req.session.userfullname);
db.query('SELECT * FROM contact where studentname = ?',
[name],
(err, result) => {
console.log("req.session.userteacherusername");
console.log(req.session.userteacherusername);
req.session.userteacherusername = result[0].username;
})
}
let output = req.session.user + req.session.userfullname + req.session.userteacherusername;
res.send(output);
req.session.save();
} else {
res.send({ message: 'Wrong username or password.' });
}
},
)
})
app.get('/login', (req, res) => {
console.log("req.session.user (get /login)");
console.log(req.session.user);
if(req.session.user) {
res.send({isLoggedIn: true, user: req.session.user})
} else {
res.send({isLoggedIn: false})
}
})
...
app.post('/logout', (req, res) => {
req.session.destroy(
function(err){
if(err){
res.send(err)
}else{
res.send("successfully logged out.")
}
}
);
})
...
app.listen(process.env.PORT || port, () => {
console.log('Successfully Running server at ' + port + '.')
});

Nuxt JS with passport local

I'm starting with Nuxt JS trying to migrate an old site with passport local and express-session, I get to make the authentication based on this repository but the main problem comes when I reload the page the users logout, its appears that Nuxt JS it's not saving my user session on the browser. I mostly sure there is something that im forgetting to implement or im not understanding. How could I save my res session token on my user browser?. Btw I have my API running on a separate port, so im not sure if there is any problem on saving session from other port. Here is my code:
Login.vue
<script>
import axios from 'axios';
export default {
data() {
return {
error : false,
form : {
username: '',
password: ''
}
}
},
created() {
if(this.$store.state.user) {
return this.$router.push('/');
}
},
methods: {
async login () {
await this.$store.dispatch('login', {
username : this.form.username,
password: this.form.password
});
this.form.password = '';
this.form.username = '';
}
},
}
</script>
Store/Index.js:
import axios from "axios";
export const state = () => ({
user: null,
});
export const mutations = {
SET_USER(state, user) {
state.user = user;
},
};
export const actions = {
nuxtServerInit({ commit }, { req }) {
if (req) {
if (
typeof req.session !== "undefined" &&
typeof req.user !== "undefined"
) {
commit("SET_USER", req.user);
}
}
},
login({ commit }, { username, password }) {
return axios({
method: "post",
url: this.$axios.defaults.baseURL + "/auth/login",
credentials: "same-origin",
data: {
username,
password
}
})
.then(res => {
if (res.data.meta.error === true) {
throw res.data;
}
return res.data.user;
})
.then(authUser => {
commit("SET_USER", authUser);
});
},
};
API Index.js
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser');
const helmet = require('helmet');
const cors = require('cors') // Srsly. Fuck Cors
const morgan = require('morgan');
const session = require('express-session');
const MySQLStore = require('express-mysql-session')(session);
const passport = require('passport');
const { database } = require('./config/keys');
const config = require('./config/config.json');
require('./lib/bAuth');
app.disable('view cache');
app.disable('x-powered-by');
app.set('port', process.env.PORT || config.port);
app.use(helmet());
app.use(cors());
app.use(morgan('dev'));
app.use(express.json());
app.use(bodyParser.urlencoded({extended: false}));
app.use(bodyParser.json());
app.use(cookieParser());
app.use(session({
name: '_hsid',
key: 'sessionKey',
secret: config.session_secret,
resave: false,
saveUninitialized: false,
store: new MySQLStore(database),
cookie : {
maxAge: 1000 * 60 * 60 *24 * 365,
},
})
);
app.use(passport.initialize());
app.use(passport.session());
app.listen(app.get('port'), () => console.log(`[✔] Website connected and running at port: ${app.get('port')}`))
Login Route:
app.post('/login', async (req,res,next) => {
req.query = req.body;
auth.authenticate('user-login', (err,user,info) => {
if(user){
req.logIn(user,(err)=>{
if(err){
return res.json({
meta: {
error: true,
msg: err
}
});
}else{
if(req.isAuthenticated()){
if(!req.user.authenticated){
return res.json({
meta: {
error: true,
msg: "Bad credentials"
}
});
}else{
return res.json({
meta: {
error: false
},
user: bAccess.cleanUser(Object.assign({}, user))
});
};
}
}
});
}else{
return res.json({
meta: {
error: true,
msg: "Bad credentials"
}
});
}
})(req,res,next);
});
Passport Config:
auth.use('user-login', new Strategy({
usernameField: 'username',
passwordField: 'password',
passReqToCallback: true
}, async (req, username, password, done) => {
const _user = await _context.query('select username,password from users where username = ?', username);
if (!_user[0]) return done(null,false);
if (!_user[0].password || !await bAccess.verifyPassword(password, _user[0].password)) {
return done(null, false);
}
done(null, _user[0], {scope : '*'});
}, ));
auth.serializeUser(function (user, done) {
done(null, user);
});
auth.deserializeUser(async (user, done) => {
done(null, user);
});

Passport req.login doesn't create req.user

i am trying to develop a login system with React,Node,Mysql,Express and Passport but i have encountered this problem. After calling req.login and passing it the userID, when i go to the route where i check for the req.user it says undefined. Here is my code for the server side.
const express = require("express");
const bodyParser = require("body-parser");
const cors = require("cors");
const app = express();
const session = require("express-session");
const { PORT = 8000 } = process.env;
const bcrypt = require("bcrypt");
const saltRounds = 10;
const cookieParser = require("cookie-parser");
const passport = require("passport");
var LocalStrategy = require('passport-local').Strategy;
const mysql = require("mysql");
/app.options("*", cors());
app.use(cors());
app.use(express.json()) // for parsing application/json
app.use(express.urlencoded({ extended: true })) // for parsing application/x-www-form-urlencoded
// app.use(cookieParser());
app.use(
session({
secret: "keyboard cat",
resave: false,
saveUninitialized: false
// cookie: { secure: false }
})
);
app.use(passport.initialize());
app.use(passport.session());
const connection = mysql.createConnection({
host: "localhost",
user: "root",
password: "qwertyhnjkl",
database: "login"
});
connection.connect(err => {
if (err) {
console.error("Error connection to database");
}
else console.log("Database connected");
});
app.get('/',function (req,res){
console.log(req.user);
console.log(req.isAuthenticated())
res.send('hello world')
});
app.post("/register", (req, res) => {
const { name, username, email, password } = req.body;
console.log(req.body);
bcrypt.hash(password, saltRounds, function(err, hash) {
connection.query(
`insert into users(Name,Username,Email,Password) values('${name}','${username}','${email}','${hash}')`,
function(error) {
if (error) console.error(error);
}
);
connection.query("SELECT LAST_INSERT_ID() as userID", (error,results,fields) =>
{
if (error) throw error;
console.log(results)
const userID = results[0].userID;
console.log("userid in query: " + userID);
req.login(userID, function(err) {
if(err) res.send(err);
else{
console.log("req.user in req.login: " + req.user)
console.log("isAuthenticated: "+ req.isAuthenticated())
console.log(req.session )
console.log('Logged in succesfully')
res.send("Logged in succesfully");
}
});
});
});
});
And this is how i handle the form in react:
submitRegister(event) {
event.preventDefault();
const data = this.state.data
axios.post("http://localhost:8000/register", {
name: data.name,
username: data.username,
email: data.email,
password: data.password
})
.then(response => {
console.log(response);
if(response.data){
console.log('Succesful signup');
this.setState({ //redirect to login page
redirectTo: '/'
})
}
}).catch(error => {
console.log("Sign up to server failed");
console.log(error)
});
}
After i request the '/' of the server and check for the session in Application->Cookies->localhost there is no session.
The insertion is well done. I get the username email hashed password in my database. i get the right userID i even get the console.log in serialize function with the right userID(the last one introduced)
req.user in req.login: 47
isAuthenticated: true
Session {
cookie:
{ path: '/',
_expires: null,
originalMaxAge: null,
httpOnly: true },
passport: { user: 47 } }
Logged in succesfully
serialize 47
This is what i get in the console when requesting the route /register from the server. Now when i go for localhost:8000 it says req.user is undefined and isAuthenticated false.
Looks like cors() was the issue here. After removing it and using proxy in package.json solved the issue.

TypeError: Cannot read property 'query' of undefined

TypeError: Cannot read property 'query' of undefined
var express = require('express')
var app = express()
var mysql = require('mysql')
var myConnection = require('express-myconnection')
var config = require('./config')
var dbOptions = {
host: config.database.host,
user: config.database.user,
password: config.database.password,
port: config.database.port,
database: config.database.db
}
app.use(myConnection(mysql, dbOptions, 'pool'))
app.set('view engine', 'ejs')
var index = require('./routes/index')
var users = require('./routes/users')
var expressValidator = require('express-validator')
app.use(expressValidator())
var bodyParser = require('body-parser')
app.use(bodyParser.urlencoded({ extended: true }))
app.use(bodyParser.json())
var methodOverride = require('method-override')
app.use(methodOverride(function (req, res) {
if (req.body && typeof req.body === 'object' && '_method' in req.body) {
// look in urlencoded POST bodies and delete it
var method = req.body._method
delete req.body._method
return method
}
}))
var flash = require('express-flash')
var cookieParser = require('cookie-parser');
var session = require('express-session');
app.use(cookieParser('keyboard cat'))
app.use(session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: true,
cookie: { maxAge: 60000 }
}))
app.use(flash())
app.use('/', index)
app.use('/users', users)
app.listen(3000, function(){
console.log('Server running at port 3000: http://127.0.0.1:3000')
})
Here is my Users.js.
var express = require('express')
var app = express()
// ADD NEW USER POST ACTION
app.post('/add', function(req, res, next){
req.assert('name', 'Name is required').notEmpty() //Validate name
req.assert('age', 'Age is required').notEmpty() //Validate age
req.assert('email', 'A valid email is required').isEmail() //Validate email
var errors = req.validationErrors()
if( !errors ) { //No errors were found. Passed Validation!
/********************************************
* Express-validator module
req.body.comment = 'a <span>comment</span>';
req.body.username = ' a user ';
req.sanitize('comment').escape(); // returns 'a <span>comment</span>'
req.sanitize('username').trim(); // returns 'a user'
********************************************/
var user = {
name: req.sanitize('name').escape().trim(),
age: req.sanitize('age').escape().trim(),
email: req.sanitize('email').escape().trim()
}
req.getConnection(function(error, conn) {
conn.query('INSERT INTO users SET ?', user, function(err, result) {
//if(err) throw err
if (err) {
req.flash('error', err)
// render to views/user/add.ejs
res.render('user/add', {
title: 'Add New User',
name: user.name,
age: user.age,
email: user.email
})
} else {
req.flash('success', 'Data added successfully!')
// render to views/user/add.ejs
res.render('user/add', {
title: 'Add New User',
name: '',
age: '',
email: ''
})
}
})
})
}
else { //Display errors to user
var error_msg = ''
errors.forEach(function(error) {
error_msg += error.msg + '<br>'
})
req.flash('error', error_msg)
res.render('user/add', {
title: 'Add New User',
name: req.body.name,
age: req.body.age,
email: req.body.email
})
}
})
I am learning node.js and want to perform CRUD operation. I am using mysql db. Right now the issue while inserting record is that it not reading the property of query.
I would like to add data in the database. But the actual result im getting is TypeError: Cannot read property 'query' of undefined
After I discussed with #Orion in chat, we found that the true error is
ERROR 1045 (28000): Access denied for user 'root'#'localhost' (using password: YES)
So the solution is reinstall the XAMPP
Please print error returned from req.getConnection(function(error, conn) {. There seems to be an error in SQL connection and so it is not returning any conn object. Don't execute SQL query if error is not null.
if(error == null){
//EXECUTE QUERIES
}else{
console.log(error)
//RETURN ERROR
}
Just a free suggestion: when you're learning new things, don't deal with so many packages, it complicates your learning.
refer this
config.js
const HOST = 'hostnname'
const USER = 'username'
const PASSWORD = 'password'
const DB_NAME = 'databasename'
module.exports = {
connectionLimit: 1,
host: HOST,
user: USER,
password: PASSWORD,
database: DB_NAME
}
user.js
var mysql = require('mysql');
var config = require('./config');
var connection = mysql.createPool(config);
exports.authentication = (req, res) => {
if (req.method === 'OPTIONS') {
console.log('!OPTIONS');
res.end();
} else {
res.set("Access-Control-Allow-Origin", "*");
res.set("Access-Control-Allow-Methods", "POST");
res.set("Access-Control-Allow-Headers", "Content-Type");
var userQuery = 'INSERT INTO users SET ? '
pool.query(userQuery, [user])
.then(results => {
res.status(200).send(results);
} else {
next();
}
})
.catch(err => {
reject(err);
})
}
};

session in nodejs express

I' m using const SessionStore = require('express-session-sequelize')(expressSession.Store); for storing the sessions.
I would like to save in session currenty user, which log to site.
here is a configuration for store:
const expressSession = require('express-session');
const SessionStore = require('express-session-sequelize')(expressSession.Store);
const Sequelize = require('sequelize');
const myDatabase = new Sequelize('analytic', 'root', '', {
host: 'localhost',
dialect: 'mysql'
});
const sequelizeSessionStore = new SessionStore({
checkExpirationInterval: 15 * 60 * 1000, // The interval at which to cleanup expired sessions in milliseconds.
expiration: 24 * 60 * 60 * 1000, // The maximum age (in milliseconds) of a valid session.
db: myDatabase
});
const cookieParser = require('cookie-parser');
app.use(cookieParser());
app.use(expressSession({
secret: '412415415415415121212121',
store: sequelizeSessionStore,
name: 'session_id',
resave: false,
saveUninitialized: false
}));
So, now for login I have this:
var express = require('express');
var url = require('url');
var router = express.Router();
var User = require('../../model').User;
var jwt = require('jsonwebtoken');
var app = require("../../application");
router.post('/authenticate', function(req, res) {
User.doLogin(req).then((result)=> {
if (result) {
if (result.error) {
if (result.error.hasOwnProperty("email")) {
res.send(400, { success: false, message: "Incorrect user / password"});
} else if (result.error.hasOwnProperty("activated")) {
res.send(400, {success: false, message: "You are not activated yet"});
}
} else {
//app.createSession(req);
req.session.user = result;
res.send(200, result);
}
}
});
});
module.exports = router;
Now, after this req.session.user = result; I have in db session table with current user data.
Now,
How can I verify is this user authenticated?
and I notice that for every request I get diferrent sessionID (is this ok)
Thanks
Hi there for user manager you can use passportjs
it's a great user manager for express and provide a high quality for handle with your user manager logic .

Resources