Persistent Session in Nodejs using MySql - mysql

new to nodejs. this might be a silly/easy question
I have an Express App and i am using mysql for persistent sessions. (using express-mysql-session to do that).
Here's code snippet from app.js:
var express = require('express');
var session = require('express-session');
var SessionStore = require('express-mysql-session');
var app = express();
app.use(session({
store: new SessionStore({
host: 'localhost',
user: 'test',
password: 'test',
database: 'test'
}),
secret: 'secret_key',
resave: false,
saveUninitialized: false
}));
routes.js
module.exports = function(app) {
app.post('/login', wrap(function* (req, res) {
var email = req.body.email;
var password = req.body.password;
var response = yield new AccountController().login(email, password);
if (response.status === 'success') {
req.session.account = {
accountId: response.accountId,
accountStatus: response.accountStatus
};
req.session.save(function(err) {
if (err) console.log('error in saving session: ' + err);
});
}
}
}));
The get and set method of express-mysql-session are called everytime a request is sent.
I wanted to know how can i set my custom data into the persistent session store without using any other library like passport.
and also how to read the store too.

Related

What am I missing? I want to store my session to MySQL database

I have my database up and running. The connection is working. I want to store my session in to the database.
Here's my code. When I run the server on my browser I get this error:
RequestError: No connection is specified for that request.
I just kept it simple in one app.js file.
var express = require('express');
var mysql = require('mysql2');
var session = require('express-session');
var MsSQLStore = require('mssql-session-store')(session);
var port = 3000;
var app = express();
var connection = mysql.createConnection ({
host: 'localhost',
user: 'root',
password: '.....',
database: 'node'
});
var sess = {
secret: 'Pearl',
resave: false,
saveUninitialized: true,
store: new MsSQLStore(options)
};
var options = {
connection: connection,
ttl: 3600,
reapInterval: 3600,
reapCallback: function() {console.log('expired sessions were removed');}
};
if(app.get('env') === 'production') {
app.set('trust proxy', 1)
sess.cookie.secure = true
}
app.use(session(sess));
connection.connect();
connection.query('Select 1 + 1 AS solution', (err, rows, fields) => {
if (err) throw err
console.log('the solution is: ', rows[0].solution)
});
app.listen(port, (req, res) => {
console.log('the server is running, ' + ' please, open your browser at http://localhost:%s', port);
});
app.get('/', (req, res) => {
res.end('Hello World');
});
In store: new MsSQLStore(options), you are attempting to use options before you've assigned it a value so it will be undefined when you try to use it. Move the definition and assignment of options to BEFORE you use it.
So, change this:
var sess = {
secret: 'Pearl',
resave: false,
saveUninitialized: true,
store: new MsSQLStore(options)
};
var options = {
connection: connection,
ttl: 3600,
reapInterval: 3600,
reapCallback: function() {console.log('expired sessions were removed');}
};
to this:
const options = {
connection: connection,
ttl: 3600,
reapInterval: 3600,
reapCallback: function() {console.log('expired sessions were removed');}
};
const sess = {
secret: 'Pearl',
resave: false,
saveUninitialized: true,
store: new MsSQLStore(options)
};
Incidentially, if you use let or const for these, then this would have been flagged by the interpreter as an error which is yet another reason to stop using var entirely.

Error in delete DB record using Node.JS and MYSQL

I'm performing CRUD operations using MYSQL and NodeJS express. Their error in deleting a record from DB, I don't know why I was getting a problem as i have copied the delete query from SQL where it is working properly. Here it is 'DELETE FROM tblltest WHERE id=?'. I manually add 'id' like 'DELETE FROM tblltest WHERE id=2' then it will delete the record from DB. Please help me out to solve this issue. Here are my lines of code.
var express = require('express');
var mysql = require('mysql');
var app = express();
var connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: '',
database: 'sampledb'
});
app.delete('/:id' , function(req , resp) {
connection.query('DELETE FROM `tblltest` WHERE `id`=?' , function(error , rows , fields){
if(!error){
console.log('Successful deleted!! \n');
resp.json(rows);
}else{
console.log('Error in deleting');
}
});
})
app.listen(1337);
You need to access the id route parameter in your delete API Node method, and then also bind this id value to the delete query:
app.delete('/:id', function(req, resp) {
var id = req.params.id;
connection.query('DELETE FROM tblltest WHERE id = ?', [id],
function(error, rows, fields) {
if (!error) {
console.log('Successful deleted!! \n');
resp.json(rows);
}
else {
console.log('Error in deleting');
}
});
})
var express = require('express');
var app = express();
var mysql = require('mysql');
var bodyParser = require('body-parser');
//start mysql connection
var connection = mysql.createConnection({
host : 'localhost', //mysql database host name
user : 'root', //mysql database user name
password : '', //mysql database password
database : 'sampledb' //mysql database name
});
connection.connect(function(err) {
if (err) throw err
console.log('You are now connected...')
})
//end mysql connection
//start body-parser configuration
app.use( bodyParser.json() ); // to support JSON-encoded bodies
app.use(bodyParser.urlencoded({ // to support URL-encoded bodies
extended: true
}));
//end body-parser configuration
//create app server
var server = app.listen(1337, "127.0.0.1", function () {
var host = server.address().address
var port = server.address().port
console.log("Example app listening at http://%s:%s", host, port)
});
//rest api to delete record from mysql database
app.delete('/employees', function (req, res) {
console.log(req.body);
connection.query('DELETE FROM `tblltest` WHERE `id`=?', [req.body.id], function (error, results, fields) {
if (error) throw error;
res.end('Record has been deleted!');
});
});

How to store my session MySQL with express-mysql-session

see code below. its not storing a session in my database. I cant figure it. I have executiion file app.js. I have everythin setup and running but storing sessions in database dont work.. I posted the same question before but got no luck...
var express = require('express');
var mysql = require('mysql2');
var path = require('path');
var session = require('express-session');
var port = 3000;
var app = express();
var MySQLStore = require('mssql-session-store')(session);
app.use(session({
secret: 'tee tee',
resave: false,
saveUninitialized: false,
store: new MySQLStore(options)
}));
var connection = mysql.createConnection ({
host: 'localhost',
user: 'root',
password: '....',
database: 'node'
});
connection.connect(function(error) {
if(error) {
throw error;
} else {
console.log("We are now successfully connected with mySQL");
}
});
var options = {
connection: connection,
ttl: 3600,
reapInterval: 3600
};
app.get('/', (req, res) => {
res.sendFile('home.html', {
root: path.join(__dirname, './views')
});
});
app.listen(port, (req, res) => {
console.log('the server is running, ' + ' please, open your browser at http://localhost:%s', port);
});
It appears as you are using mssql-session-store (Microsoft SQL) to connect to MySQL.
Try using the npm package express-mysql-session:
https://www.npmjs.com/package/express-mysql-session
Like MySQL and MSSQL, there are many variants of SQL and SQL like databases so it is important you are precise with the database you are using.
Your line (below) should be the only issue. It is specifying the use of the Microsoft SQL session store package when you are trying to use the MySQL session store.
var MySQLStore = require('mssql-session-store')(session);
By changing it to
var MySQLStore = require('express-mysql-session')(session);
You specify the use of the mysql session store (Make sure you download the NPM package above first)

Express session not saving after successful authentication

I am implementing a login system for my project. This project is divided in two, a server portion in NodeJS, and a client portion in ReactJS. Both of these are wrapped up in docker containers including a couple more containers for mySQL and PHPMyAdmin. Thus far, I've been able to connect to databases in the mySQL container and insert into a table for Users. Now, I'm trying to log in with a user, then save this user information if the login is successful, and return the session when asked. So I call the sign in get request as follows in the front-end:
export function signIn(table, userName, password) {
return axios.get(`http://localhost:8000/signin`, {
params: {
table,
userName,
password,
},
}, {withCredentials: true}).then((response) => {
if (response.data.length === 1) {
return "success";
}
return response;
});
}
Then in the server, I receive and work with the information like this:
const bcrypt = require('bcryptjs');
const bodyParser = require('body-parser');
const cors = require('cors');
const express = require('express');
const multer = require('multer');
const mysql = require('mysql');
const nodeMailer = require('nodemailer');
const session = require('express-session');
const smtpTransport = require('nodemailer-smtp-transport');
const app = express();
const upload = multer();
app.use(session({
secret: 'secret',
resave: true,
saveUninitialized: true,
cookie: {
maxAge: 7 * 24 * 60 * 60 * 1000,
secure: false,
}
}));
app.use(cors(({
credentials: true,
}));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
const pool = mysql.createPool({
host: process.env.MYSQL_HOST_IP,
user: process.env.MYSQL_USER,
password: process.env.MYSQL_PASSWORD,
database: process.env.MYSQL_DATABASE,
});
app.get('/signin', (req, res) => {
const { table, userName, password } = req.query;
pool.query(`select * from ${table} where username = '${userName}'`, (err, results) => {
if (err) {
res.send(err);
} else {
if (bcrypt.compareSync(password, results[0].password)) {
req.session.userId = results[0].id;
req.session.name = results[0].name;
req.session.email = results[0].email;
req.session.sex = results[0].sex;
req.session.img = results[0].img;
req.session.userName = results[0].username;
req.session.about = results[0].about;
req.session.save(err => console.log(err));
res.send(results);
} else {
res.send([]);
}
}
});
});
Then I expect to call it with another request to get the information back and use to to modify a front end component's state like this (both of these requests are in the same file):
app.get('/loggeduser', (req, res) => {
if (req.session.userId) {
const {
userId,
name,
email,
sex,
img,
userName,
about,
} = req.session;
const userInfo = {
userId,
name,
email,
sex,
img,
userName,
about,
};
res.send(userInfo);
} else {
res.send({});
}
});
and the component calls it like this:
export function getLoggedUser(setUserInfo) {
axios.get(`http://localhost:8000/loggeduser`, {}, {withCredentials: true}).then((response) => {
setUserInfo(response.data);
});
}
But the information never gets sent back, because req.session.userId is always undefined. I tried adding a console.log to output req.session and whenever I refresh the page (at which time the component calls getLoggedUser) the server image outputs req.session with a created time that is just a few seconds ago from the moment I refresh the page, meaning it gets created anew whenever I refresh. Is it that this is not saving properly because it's a get request and not a route? Please let me know if I may be missing something vital for this to work.

How to create login endpoint using express-session and express-mysql-session

I want to create a secure login. I'd like to add session but I can't figure out how they should be used together.
I have 2 codes, one code came from express-mysql-session and another code which I wrote and has the login (/api/login) endpoint.
Below is the code which I copied from the readme.md of express-mysql-session and it works.
var express = require('express');
var app = module.exports = express();
var session = require('express-session');
var MySQLStore = require('express-mysql-session')(session);
var options = {
host: 'localhost',
port: 3306,
user: 'root',
password: 'password',
database: 'session_test'
};
var sessionStore = new MySQLStore(options);
app.use(session({
key: 'session_cookie_name',
secret: 'session_cookie_secret',
store: sessionStore,
resave: true,
saveUninitialized: true
}));
Here is the output on the terminal. The code above ran well but not really sure what it did. I see it has established connection to the locally running mysql using netstat command
tcp4 0 0 127.0.0.1.3306 127.0.0.1.52470 ESTABLISHED
tcp4 0 0 127.0.0.1.52470 127.0.0.1.3306 ESTABLISHED
then the output
$ DEBUG=express-mysql-session* node index.js
express-mysql-session:log Creating session store +0ms
express-mysql-session:log Setting default options +2ms
express-mysql-session:log Creating sessions database table +46ms
express-mysql-session:log Setting expiration interval: 900000ms +42ms
express-mysql-session:log Clearing expiration interval +0ms
Then below is the basic login auth endpoint I created using Express. This works but I want to add express-session, express-mysql-session as well as use crypt, bcrypt or scrypt-for-humans but not sure how to integrate it.
const express = require('express');
const bodyParser = require('body-parser');
const mysql = require('mysql');
const app = express();
app.use(bodyParser.json()); // to support JSON-encoded bodies
app.use(bodyParser.urlencoded({ // to support URL-encoded bodies
extended: true
}));
app.set('port', (process.env.API_PORT || 8000));
const connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : 'password',
database : 'authdb'
});
connection.connect(function(err) {
if (err) {
console.error('error connecting: ' + err.stack);
return;
}
console.log('connected as id ' + connection.threadId);
});
app.post('/api/login', function(req, res) {
const user_id = req.body.user_id;
const password = req.body.password;
let response = {};
res.setHeader('Content-Type', 'application/json');
connection.query('SELECT password from user WHERE `username` = "' + user_id + '"' , function(err, rows) {
if (err) throw err;
if (rows.length > 0) {
if (password === rows[0].password) {
response.status = 200;
response.message = "authenticated";
response.authenticated = true;
response.user_id = user_id;
} else {
response.status = 403;
response.message = "Login failed!";
response.authenticated = false;
response.user_id = user_id;
}
} else {
response.status = 403;
response.message = "Login failed!";
response.authenticated = false;
response.user_id = user_id;
}
res.status(response.status).send(JSON.stringify(response));
});
});
app.listen(app.get('port'), () => {
console.log(`Find the server at: http://localhost:${app.get('port')}/`);
});
I got it working and quite happy with the results. My login endpoint is working great! I now have more ideas on how to make it better as well. Here is the screenshot of the REST client - http://i.imgur.com/fJOvmzh.png and below is the endpoint
app.post('/api/login', function(req, res) {
const user_id = req.body.user_id;
const password = req.body.password;
let response = {};
res.setHeader('Content-Type', 'application/json');
connection.query('SELECT * FROM authdb.users as authusers inner join authdb.passwords as hashed on authusers.email = hashed.email WHERE authusers.email = "' + user_id + '"' , function(err, rows) {
if (err) throw err;
Promise.try(function(){
return scrypt.verifyHash(password, rows[0].password);
}).then(function(){
var sess = req.session;
if (sess.views) {
sess.views++;
} else {
sess.views = 1
}
response = { status: 200, message: "Login successful!", authenticated: true, user_id: user_id, views: sess.views }
res.status(response.status).send(JSON.stringify(response));
}).catch(scrypt.PasswordError, function(err){
response = { status: 403, message: "Login failed!", authenticated: false, user_id: user_id }
res.status(response.status).send(JSON.stringify(response));
});
});
});
To make it secure, I'll setup an EC2 behind an ELB which terminates all SSL connections and sends all traffic in clear to the NodeJS running my Express auth API spawned by PM2 or other better balancers. The AWS secgroup will only accept traffic whose source is the ELB.