I am trying to manage user sessions in nodejs. I have built a dashboard where people will be able to manage their products for inventory and such. I basically have it running right now where a user logs in, and it stores there username in a global variable, and then userAuth gets set to true. Obviously in a prod env this would not work, so I am trying to manage each session. the user should log on, and they should have their own session, and all their database creds should be pulled from my master table, and then used for that specific session. multiple users should be able to use this and edit their products and inventory at the same time. I have tried express-session, but no luck, I'm doing something wrong but not sure where to start really. here's my login code:
//LOGIN FUNCTIONALITY
app.post("/login", (req, res) => {
//defining variables for users username & password inputs
const inputUsername = req.body.inputUsername;
const inputPassword = req.body.inputPassword;
//functionality to query db by username
var userLogin = "select * from login where USERNAME = ?";
ibmdb.open(ibmdbconnMaster, function (err, conn) {
if (err) return console.log(err);
conn.query(userLogin, [inputUsername], function (err, rows) {
if (err) {
console.log(err);
}
//if the query returns results that are > 0
if (rows.length > 0) {
var pass = "";
userSessionId = req.body.sessionID
var sessUsername = userUsername
//loop for getting those values that correspond with the username of the user
for (var i = 0; i < rows.length; i++) {
userUsername = rows[i]["USERNAME"];
pass = rows[i]["PASSWORD"];
firstName = rows[i]["FN"];
lastName = rows[i]["LN"];
company = rows[i]["COMPANY"];
ibmdbconnDash = rows[i]["DBCONNSTRINGDASH"];
ibmdbconnBlog = rows[i]["DBCONNSTRINGBLOG"];
mailerStatus = rows[i]["MAILERSTATUS"];
//these will be more secure when time comes
cloudinaryName = rows[i]["CLOUDINARYNAME"];
cloudinaryKey = rows[i]["CLOUDINARYKEY"];
cloudinarySecret = rows[i]["CLOUDINARYSECRET"];
}
//comparing user input password to hashed db password
bcrypt.compare(inputPassword, pass, function (err, result) {
console.log("result is " + result);
//if the result of the compare is true, then redirect to the index function
if (result == true) {
console.log("login works");
userAuth = "true"
res.redirect("/index");
} else {
//if compare returns false, re-render login page
userAuth = "false";
res.render("login.ejs");
alert("Incorrect username or password. Please try again");
}
});
//if the entire query returns rows < 1 (username and password don't match, then re-render login page)
} else {
userAuth = "false";
res.render("login.ejs");
alert("Incorrect username or password. Please try again");
}
conn.close(function () {
console.log("closed the function /login");
});
});
});
});
global variables
var userAuth = ""
var userName = "";
var firstName = "";
var lastName = "";
var company = "";
var password = "";
var ibmdbconnMaster =
"db2 conn string";
var ibmdbconnDash = "";
var ibmdbconnBlog = "";
var userUsername = "";
var mailerStatus = "";
var cloudinaryName = "";
var cloudinaryKey = "";
var cloudinarySecret = "";
I have tried implementing sessions using express-sessions, the code I had set up for that was the standard code from their site:
app.use(session({
secret: "sec",
resave: false,
uninitialized: true,
}))
main index / landing page (dashboard) function
//DEFINING GLOBAL VARIABLES FOR AUTH
var sessionID = "";
var numOfOrders = "";
var numOfUsersM = "";
var userAuth = ""
var userName = "";
var firstName = "";
var lastName = "";
var company = "";
var password = "";
var ibmdbconnMaster =
"db conn string";
var ibmdbconnDash = "";
var ibmdbconnBlog = "";
var userUsername = "";
var mailerStatus = "";
var cloudinaryName = "";
var cloudinaryKey = "";
var cloudinarySecret = "";
//manage sessions
app.use(session({
secret: 'secret-key',
resave: true,
saveUninitialized: true,
}))
//rendering login page
app.get("/login", (req, res) => {
res.render("login.ejs");
});
/
//LOGIN FUNCTIONALITY
app.post("/login", (req, res) => {
// console.log("sessionsid is: " + req.body.sessionID)
// sessionID = req.body.sessionID
//defining variables for users username & password inputs
const inputUsername = req.body.inputUsername;
const inputPassword = req.body.inputPassword;
//functionality to query db by username
var userLogin = "select * from login where USERNAME = ?";
ibmdb.open(ibmdbconnMaster, function (err, conn) {
if (err) return console.log(err);
conn.query(userLogin, [inputUsername], function (err, rows) {
if (err) {
console.log(err);
}
//if the query returns results that are > 0
if (rows.length > 0) {
var pass = "";
//var userUsername = ""
userSessionId = req.body.sessionID
var sessUsername = userUsername
//loop for getting those values that correspond with the username of the user
for (var i = 0; i < rows.length; i++) {
var userUsername1 = rows[i]["USERNAME"];
pass = rows[i]["PASSWORD"];
firstName = rows[i]["FN"];
lastName = rows[i]["LN"];
company = rows[i]["COMPANY"];
ibmdbconnDash = rows[i]["DBCONNSTRINGDASH"];
ibmdbconnBlog = rows[i]["DBCONNSTRINGBLOG"];
mailerStatus = rows[i]["MAILERSTATUS"];
cloudinaryName = rows[i]["CLOUDINARYNAME"];
cloudinaryKey = rows[i]["CLOUDINARYKEY"];
cloudinarySecret = rows[i]["CLOUDINARYSECRET"];
}
//comparing user input password to hashed db password
bcrypt.compare(inputPassword, pass, function (err, result) {
console.log("result is " + result);
//if the result of the compare is true, then redirect to the index function
if (result == true) {
console.log("login works");
var userAuth1 = "true"
//successful login
req.session.user = {
userUsername1,
userAuth1
}
console.log("rquu1 " + req.session.user.userUsername1)
res.redirect("/index");
} else {
//if compare returns false, re-render login page
userAuth1 = "false";
res.render("login.ejs");
alert("Incorrect username or password. Please try again");
}
});
//if the entire query returns rows < 1 (username and password don't match, then re-render login page)
} else {
userAuth = "false";
res.render("login.ejs");
alert("Incorrect username or password. Please try again");
}
conn.close(function () {
console.log("closed the function /login");
});
});
});
});
//function for logout page
app.get("/logout", (req, res) => {
userAuth = "false";
res.render("login.ejs");
});
//RENDERING INDEX PAGE WITH INFORMATION ABOUT PRODUCTS AND ANALYTICS
app.get("/index", (req, res) => {
// if (userAuth == "true") {
if (req.session.user) {
console.log(req.session.user)
console.log("username is: " + userName);
pageName = "/index";
numOfOrdersFun(req, res, numOfOrders)
//end of location manager
//initializing counter
var counterTest2 = "select * from VISITORS";
ibmdb.open(ibmdbconnDash, function (err, conn) {
if (err) return console.log(err);
conn.query(counterTest2, function (err, rows) {
if (err) {
console.log(err);
}
for (var i = 0; i < rows.length; i++) {
var dbCountCurrent = rows[i]["NUM"];
}
console.log("currentCount " + dbCountCurrent);
conn.close(function () {
console.log("closed the function /login");
});
//showing information for products
var showingDBINFO = "SELECT * FROM PRODUCTS";
ibmdb.open(ibmdbconnDash, function (err, conn) {
if (err) return console.log(err);
conn.query(showingDBINFO, function (err, rows) {
if (err) {
console.log(err);
}
//rendering page with all users information, products, and data from login. also a redirect from the login info.
res.render("index", {
page_title: "index",
data: rows,
userName: userName,
FN: firstName,
LN: lastName,
CO: company,
dbcc: dbCountCurrent,
numOfOrders: numOfOrders,
mailerStatus: mailerStatus,
});
conn.close(function () {
console.log("closed the function /index);
});
});
});
});
});
} else {
req.session.user.userAuth1 == "false"
res.render("login.ejs");
}
});
but now im confused on how to manage each session individually when their are so many global variables I have that are needed for each session, and would users be able to use the app simultaneously?
thanks for the help!
When using express-session you can use the req.session object and store your preferred data. In your concrete example you could set all the information about the user you need later in your code to req.session.user.
Tiny example:
//successful login
req.session.user = {
userName,
firstName
}
If you need to access any information about the user later, just use req.session.user.userName for instance.
This data is stored server-side and is also available in new requests.
Please also note that the secret shouldn't be the default, instead use a strong & generated password nobody knows.
Related
I need to Update MYSQL data using JS after I receive an AJAX Post request
I made a variable for the MYSQL Update Query and I'm passing in the field to be updated, new value, row to be updated as an array. But for some reason those variables are read with single quotes(') which, I believe, is causing me a syntax error.
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var MYSQL = require('mysql');
var server = require('http').createServer(app);
//declaring var 'conn' for MYSQL.createPool
let columns = new Array();
// Piece of code Starting the Server
// Routing
app.use(bodyParser.json()); // for parsing application/json
app.use(bodyParser.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded
app.use(express.static(path.join(__dirname, 'public')));
app.post('/', function (req, res) {
updateWorkbook(req.body);
res.send('Thanks for the data.');
});
//This is the function extracts the row, field value that need to be updated from the AJAX request
function updateWorkbook( data ){
getcolumns().then( function (columns) {
console.log("Columns got returned to Updateworkbook function")
for (let d = 0; d < data.length; d++) {
let rowToUpdate = data[d].id.replace('row_', '').split('_')[0];
let fieldToUpdate = data[d].id.replace('row_', '').split('_')[1];
let newValue = data[d].value;
console.log('row,field,value: ' + rowToUpdate + '|' + fieldToUpdate + '|' + newValue);
let key_to_replace;
for(let i = 0; i < columns.length; i++) {
let looper = columns[i].toLowerCase()
if (looper === fieldToUpdate) {
key_to_replace = columns[i]
}
}
let field_to_replace = key_to_replace.toString();
console.log(field_to_replace) //It prints out a normal string value here
updatemysql(field_to_replace, newValue, rowToUpdate);
}
});
};
//This is the function which updates MYSQL data
function updatemysql(field, newval, row) {
var sql = "UPDATE mydb.mytable SET ? = ? WHERE ROW_ID = ?;";
conn.getConnection( function (err, connection) {
if (err){
return cb(err);
connection.release();
}
console.log("Connection got established")
conn.query(sql, [field, newval, row], function (error, results){
if (error){
throw error;
connection.release();
}
console.log('Data Updated');
connection.release();
});
});
}
//Function to extract all columns from MYSQL and stores them in an array
function getcolumns() {
return new Promise(function(resolve, reject) {
console.log("getcolumns got initiated")
conn.getConnection( function (err, connection) {
if (err){
return cb(err);
connection.release();
return reject(err);
}
else {
var sql = "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'mydb' AND TABLE_NAME = 'mytable';"
conn.query(sql, function (error, results){
for (let i = 0; i < results.length; i++) {
columns.push(results[i]['COLUMN_NAME'])
}
resolve(columns);
console.log("Extracted columns")
connection.release();
});
}
});
});
};
Here's the error I receive:
Error: ER_PARSE_ERROR: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''Source_of_Phone_Number_' = 'Test' WHERE ROW_ID = '1'' at line 1`
Source_of_Phone_Number_ is the key_to_replace.
Test is the newValue.
1 is the Row_ID.
There is a problem in function updatemysql(), which uses the following SQL :
var sql = "UPDATE mydb.mytable SET ? = ? WHERE ROW_ID = ?;";
You cannot pass a column name as a parameter.
You would need to change this to :
var sql = "UPDATE mydb.mytable SET " + field + " = ? WHERE ROW_ID = ?;";
Accordingly, only two parameters should be passed to the query :
conn.query(sql, [newval, row], function (error, results){ ... });
How i can set result of a COUNT query to variable:
I have a function:
exports.someFunction = function (req, res) {
var user = req.session.user,
userId = req.session.session_id;
if(userId == null){
res.redirect("/login");
return;
}
let sql = `SELECT COUNT(*) FROM table WHERE id_one = ? AND status = ?`;
let post = [userId, 2];
connection.query(sql, post, (err, result) => {
if(err){
console.log(err)
}
res.json(result);
let a = setValue(result);
console.log(a);
});
};
function setValue (result) {
let a = result;
}
When I set result of query to variable a I get undefined. Please help me fix this problem.
You could use an alias for an easy access to the column name
let sql = `SELECT COUNT(*) mycount FROM table WHERE id_one = ? AND status = ?`;
.....
and access to the first element as
console.log(result[0].mycount);
I need to display in a html page the results of a GET request to a mysql database which are given in JSON format. I am using express js with bootstrap and I am basically asking how to display the results of a GET request done in node.js in a html page.
This is the code that performs the GET request, tell me if I have to be more clear please
app.route('/zigbee/:action').get(function (req, res) {
var connectionZ = mysql.createConnection({
host : 'localhost',
user : '',
password : '',
database : 'ZigBeeNetwork'
});
connectionZ.connect();
if (req.param('action') == 'zi') {
//route utilizzata per inserire dati, la data รจ inserita automaticamente tramite la funzione Date()
name = req.param('name');
temp = req.param('temp');
hum = req.param('hum');
date = Date();
if(!name){name = null;}
if(!temp){temp = null;}
if(!hum){hum = null;}
var queryString = 'INSERT INTO ZigBeeTH (id, Arduino, Temp, Hum, Data) VALUES (NULL, "'+name+'", '+temp+', '+hum+', "'+date+'")';
connectionZ.query(queryString, function(err, rows, fields) {
if (err) throw err;
else{
console.log('Query performed');
res.send('Query performed');
}
});
}
if (req.param('action') == 'zs') {
//route per cercare dei dati basandosi su nome e temperatura
name = req.param('name');
temp = req.param('temp');
hum = req.param('hum');
date = Date();
var app='';
if (name) {
app += 'Arduino="'+name+'"';
}
if(temp) {
if(app) {
app+=' AND ';
}
app += 'Temp="'+temp+'"';
}
if(hum){
if(app) {
app+=' AND ';
}
app += 'Hum="'+hum+'"';
}
var queryString = 'SELECT * FROM ZigBeeTH WHERE '+app;
console.log('Test '+queryString );
connectionZ.query(queryString, function(err, rows, fields) {
if (err) throw err;
var JSONObject = JSON.stringify(rows);
res.send(JSONObject);
});
}
});
I have a piece of code that needs to do the following :
For each Sensor objects in the array, get the Template ID first.
Search the Template Schema DB, get the zipcode of the corresponsing Template ID got.
From the zipcode, generate the URI
Make the requestAPI call
Get the output of the API and store it in the DB for that sensor object.
I am having problem with step 5, storing the result in the DB for each SenObject. I guess the problem is since newSensorObjectRes is defined locally in the test(), it can't be used outside. How else can I store the results for each object?
var arr = [];
function SenObj (id)
{
this.Objnum = 10;
this.Template = id;
this.Type = "AirFlow";
this.UserID = "Jessi";
}
// To store the results from the AIR API
var sensorResults = new Schema({
//reqId: {type: Number, required: true, unique: true},
//sensorId: {type: Number},
SenObj: {type: Number},
status: {type: String, default: 'Undefined'}
})
var SensorObjectRes = connUserSensors.model('SensorObjectRes', sensorResults)
//API:To create Sensor Objects when user requests for template
// When user makes a request to create a new Template,we get the tempate ID he has requested.
// We use the ID to create a Sensor Object.We might need the request id too here ??
// The array arr[] holds all the sensor obects..
app.get('/ProvisionTemplate/:id', function (req, res) {
var id = req.params.id;
console.log("Server recieved a GET /ProvisionTemplate/" + id + " request");
Template.findOne({templateId: parseInt(id)},function (err, data) {
if (err) return console.error(err);
console.log(data);
res.json(data);
// Create an Object here
var user1 = new SenObj(id);
console.log(user1.UserID);
arr.push(user1);
});
});
console.log("The array objects are :");
for (i = 0; i < arr.length; i++)
{
console.log(arr[i]);
}
var output = ""
function test()
{
var zip = "";
console.log("Interval reached");
for (i = 0; i < arr.length; i++)
{
// For each Sensor objects in the array, get the Template ID first.
// Search the Template Schema DB, get the zipcode of the corresponsing Template ID got.
// From the zipcode, generate the URI
// Make the requestAPI call
// Get the output of the API and store it in the DB for that sensor object.
console.log(arr[i]);
console.log(arr[i].Template);
var tem = arr[i].Template;
Template.findOne({templateId: tem},function (err, data)
{
if (err) return console.error(err);
console.log(data.zipcode);
zip = data.zipcode;
var uri_1 = "http://www.airnowapi.org/aq/observation/zipCode/current/?format=application/json&zipCode=";
var uri_2 = "&distance=25&API_KEY=1035C2AC-CDB8-4540-97E4-0E8D82BA335A";
var url = uri_1 + zip + uri_2;
console.log(url);
requestApi(url, function (error, response, body)
{
if (!error && response.statusCode == 200)
{
console.log(body);
//console.log(arr[i])
var newSensorObjectRes = new SensorObjectRes({"SenObj": 1 ,"status": body});
newSensorObjectRes.save(function (err, data)
{
if (err) return console.log("error updating");
console.log(data);
})
}
})
});
}
}
var interval = setInterval(test, 10000);
newSensorObjectRes.find(function (err, data)
{
if (err)
{
console.log("Could not find EC2Server db");
return;
}
console.log(data)
})
I believe the issue is having a for loop in your test function. You could be making all your Template requests before you get a response. Try using recursion instead. This will assure that your requests are made in an orderly fashion. Something like this...`
function test(i)
{
if(i == arr.length){
console.log("done");
return;
}
var zip = "";
console.log("Interval reached");
console.log(arr[i]);
console.log(arr[i].Template);
var tem = arr[i].Template;
Template.findOne({templateId: tem},function (err, data)
{
if (err) return console.error(err);
console.log(data.zipcode);
zip = data.zipcode;
var uri_1 = "http://www.airnowapi.org/aq/observation/zipCode/current/?format=application/json&zipCode=";
var uri_2 = "&distance=25&API_KEY=1035C2AC-CDB8-4540-97E4-0E8D82BA335A";
var url = uri_1 + zip + uri_2;
console.log(url);
requestApi(url, function (error, response, body)
{
if (!error && response.statusCode == 200)
{
console.log(body);
var newSensorObjectRes = new SensorObjectRes({"SenObj": 1 ,"status": body});
newSensorObjectRes.save(function (err, data)
{
if (err) return console.log("error updating");
console.log(data);
test(i+1);
})
}
})
});
}
test(0);
So at my server app when I get a socket request I send data based on what user is requesting the information...
server.on('connection', function(socket) {
socket.on('login', function(data) {
connection.query('SELECT * FROM users WHERE name = ? AND password = ? LIMIT 1', [data.name, data.password], function(err, result) {
if(result.length === 0)
{
socket.emit('login-failed');
}
else
{
if(users.check(result[0].name))
{
result[0].socket = socket.id;
users.add(result[0]);
console.log(colors.yellow('User: ' + result[0].name + ' connected.'));
socket.emit('login-success');
}
}
});
});
So when a user logs in I save some information like username, password, socketid.
var userList = [];
exports.add = function(data)
{
userList.push(data);
}
exports.check = function(data)
{
for(var i = 0; i < userList.length; i++)
{
if(userList[i].name === data)
{
return false;
}
}
return true;
}
exports.remove = function(id)
{
for(var i = 0; i < userList.length; i++)
{
if(userList[i].socket === id)
{
var index = userList.indexOf(i);
userList.splice(index, 1);
return true;
}
}
return false;
}
So as you can see Im saving users data that I will access later for example on here
socket.on('test', function(data) {
if(users.remove(socket.id)) console.log('Yes');
});
But the only way I have to identify a socket is by using its socket.id, now my question is if I can really trust socketid or if I should use another 'system' to actually manage my users logic.
I cant really figure any other system to actually check what socket is calling my server