I am currently practicing nodeJS and I would like to achieve something like this :
I am trying to check if another session with the same session.username exists. and if it does, display a warning. I am doing it this way :
app.post('/login', (req, res) => {
let options = {"username": req.body.username, "error": null};
if(!req.body.username) {
options.error = "username required nobi";
res.render('login', options);
} else if (req.body.username == req.session.username) {
res.redirect('/');
} else {
req.sessionStore.all( (err, sessions) => {
if(!err) {
let isUsed = false;
let i=0;
for(i; i < sessions.length; i++) {
let session = JSON.parse(sessions[i]);
if (session.username == req.body.username) {
err = "name already taken";
isUsed = true;
break;
}
}
}
if (err) {
options.error = err;
res.render('login', options);
} else {
req.session.username = req.body.username;
res.redirect("/");
}
});
}
});
It is not working : I am connecting on chrome and IE with the same username. I do not want that to be possible
as an illustration (if needed) :
{ If9a9SgOoq7roW8Za84CouSEzgqDs1Q3:
{ cookie: { originalMaxAge: null, expires: null, httpOnly: true, path: '/' },
username: 'pseudo' },
MBs41iJmoQpLLCDhP8aFAk5PWAZ_ZQSV:
{ cookie: { originalMaxAge: null, expires: null, httpOnly: true, path: '/' },
username: 'pseudo' } }
app.post('/login', (req, res) => {
// You can store username in res.locals.username after auth
// It's not necessary to pass it into render.
let username = req.body.username;
if(!username)
return res.render('login', {error: 'username required nobi'});
if (username == req.session.username)
return res.redirect('/');
if (username && username != req.session.username)
return ... // maybe destroy current session?
req.sessionStore.all( (err, sessions) => {
if (err)
return res.render('login', {error: err.message});
let isUsed = Object.keys(sessions).some((id) => sessions[id].username == username);
if (isUsed)
return res.render('login', {error: 'Already used'});
req.session.username = username;
res.locals.username = username;
res.redirect('/');
});
});
Related
I am new to express and using express-session to manage login(s) in my application.
I have followed a blog and declared my session as below:-
app.use(session({
secret:'Keep It Secret',
name : 'uniqueSessionID',
resave : true,
saveUninitialized : true,
cookie : { secure : false, maxAge : 3600000, loggedIn : false, username : "" }
}));
The problem is that on a successful login I'm updating the session and printing it, which outputs to:-
Session {
cookie: {
path: '/',
_expires: 2021-12-27T13:16:17.355Z,
originalMaxAge: 3600000,
httpOnly: true,
secure: false,
loggedIn: true,
username: 'pushkar#gmail.com'
}
}
But after that when I authenticate the routes, the session remains unchanged just like below:-
Session {
cookie: {
path: '/',
_expires: 2021-12-27T13:16:17.355Z,
originalMaxAge: 3600000,
httpOnly: true,
secure: false
}
}
I have tried all and need help.
This is my login where I login and make the session:-
const login = (req, res, next) => {
console.log(req.body);
const email = req.body.email;
const password = req.body.password;
if(email == "" && password == ""){
req.flash("message","please fill in the required fields");
res.redirect("/admin/login");
}
else if(email == ""){
req.flash("message", "please fill in the email");
res.redirect("/admin/login");
}
else if(password == ""){
req.flash("message", "please fill in the password");
res.redirect("/admin/login");
}
else {
user.findOne({email : email}, function(err, data){
debugger;
if(err){
req.flash("message", "Username not found");
res.redirect("/admin/login");
}
else {
if(data.password == password){
req.session.cookie.loggedIn = true;
req.session.cookie.username = email;
req.session.save(function(err) {
if (err) console.log(err);
})
console.log(req.session);
}
else{
req.flash("message", "Invalid Password");
res.redirect("/admin/login");
}
res.redirect("/admin/dashboard");
}
})
}
};
and This is my authentication function:-
exports.authenticated = (req, res, next) => {
debugger;
console.log(req.session);
if(req.session.cookie.loggedIn) {
next();
}
else {
res.redirect("/admin/login");
}
}
It's incorrect to set the value, you want to save, to req.session.cookie it the place where you set up uniqueSessionID cookie options, not saved value.
See this tutorial for example
try
//to write
req.session.loggedIn = true;
req.session.username = email;
//to read
if(req.session.loggedIn) {
next();
}
if all works, maybe you will want to make the session permanent between restarts, so see next
Example with permanent storage
I'm using the express-session package and I want to change the variable "_id" in the session.
Here my session init
app.use(session({
secret: "secretshhhhhh",
resave: true,
saveUninitialized: false,
}))
After the login page I try to store the id with these few lines:
req.session._id = user._id.toString()
req.session.save(function (err) {
req.session.save(function (err) {
console.log(req.session)
})
})
The console.log print the session with the id, but when I try to get the _id in an other page express send me back a null object. Here an exemple of printing session without the _id
return res.status(200).send(req.session);
I tried many methods but none of these worked for me.
EDIT:
Here my whole function to put it in session
module.exports.login_post = async function (req, res) {
User.findOne({ email: req.body.email }, function (err, user) {
if (user == null) {
return res.status(400).send({
message: "User not found"
})
}
else {
if (user.validPassword(req.body.password)) {
req.session._id = user._id.toString()
req.session.save(function (saveErr) {
req.session.reload(function (reloadSave) {
console.log(req.session, saveErr, reloadSave)
})
})
}
}
})
}
Here my whole function to get it from session
module.exports.session_get = function(req, res) {
return res.status(200).send(req.session);
}
module.exports.session_destroy = function(req, res) {
req.session.destroy();
return res.status(200).send({
message: "Session detroyed"
});
}
So I am having a problem with Passport I've been trying to move from my original method of authentication because Passport supports other types like Google and GitHub. I'm trying to implement the local authentication and it doesn't seem to be working, even after looking up many articles and they all don't work.
This is at the top of the code:
const cookieExpirationDate = new Date();
cookieExpirationDate.setDate(cookieExpirationDate.getDate() + 7);
app.use(session({
secret: secret_key,
store: sessionStore,
resave: true,
saveUninitialized: true,
cookie: {
httpOnly: true,
sameSite: 'strict',
expires: cookieExpirationDate
}
}));
// PASSPORT //
app.use(passport.initialize());
app.use(passport.session());
passport.use('local', new LocalStrategy({
usernameField: 'username',
passwordField: 'password',
passReqToCallback: true //passback entire req to call back
}, async function (req, username, password, done) {
if (!username || !password) {
return done(null, false, {message: 'Please complete the form!'})
}
const reqBody = {
response: req.body['h-captcha-response'],
secret: captcha_key
}
let axiosResult = await axios.post('https://hcaptcha.com/siteverify', qs.stringify(reqBody), {
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
})
if (axiosResult.data.success === true) {
let results = await runQuery('SELECT * FROM accounts WHERE (username = ? OR email = ?)', [username, username])
const forwarded = req.headers['x-forwarded-for']
const ip = forwarded ? forwarded.split(/, /)[0] : req.connection.remoteAddress
if (!results.length) {
let amtLeft = await loginAttempts(ip);
if (amtLeft > 1) {
return done(null, false, {message: `Incorrect Username and/or Password! (${amtLeft} attempt(s) left)`});
} else {
return done(null, false, {message: `You must wait 15 minutes before trying again!`});
}
}
let user = results[0]
let isMatch = await bcrypt.compareSync(password, user.password)
if (!isMatch) {
let amtLeft = await loginAttempts(ip);
if (amtLeft > 1) {
return done(null, false, {message: `Incorrect Username and/or Password! (${amtLeft} attempt(s) left)`});
} else {
return done(null, false, {message: `You must wait 15 minutes before trying again!`});
}
} else {
if (user.activation_code === "activated") {
return done(null, user)
} else {
return done(null, false, {message: 'Check your email for an activation email!'})
}
}
} else {
return done(null, false, {message: `You must complete the captcha!`});
}
}
));
passport.serializeUser(function (user, done) {
done(null, user.id);
});
passport.deserializeUser(async function (usrid, done) {
let results = await runQuery('SELECT * FROM accounts WHERE id = ?', usrid)
done(results[0]);
});
Login API part:
app.post('/login_sys', regularFunctions, function (req, res, next) {
passport.authenticate('local', {failWithError: true}, function (error, user, info) {
if (error) {
return res.status(500).json(error);
}
if (!user) {
return res.status(401).json(info);
}
return res.status(200).send('Success')
})(req, res, next);
})
regularFunctions:
let regularFunctions = [
bodyParser.urlencoded({extended: true}),
bodyParser.json(),
function (req, res, next) {
console.log('Authenticated: ' + req.isAuthenticated())
if (req.isAuthenticated()) {
req.session.loggedin = true;
return next();
} else {
req.session.loggedin = false;
return next();
}
}
]
I need it to return some sort of notification to the client if it fails or succeeds because I have a little pop up that lets them know they are getting redirected if it works and to notify them of their attempts left. The problem is it works and says that it logged in but when I refresh the page it never did.
Ok just found out the answer after searching for a while, I had to use req.login inside the login_sys route.
I am using Syncfusion Scheduler in my MEAN-stack application. This is the code for handling getting / inserting / editing the appointments:
MongoClient.connect(url, function (err, db) {
if (err) throw err;
var dbo = db.db("meanstacknew");
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
app.post("/GetData", (req, res) => {
var user = req.user;
const token = req.get("authorization");
dbo.collection('ScheduleData').find({}).toArray((err, cus) => {
res.send(cus);
console.log(token);
});
});
app.post("/BatchData", (req, res) => {
console.log(req.body);
var eventData = [];
if (req.body.action == "insert" || (req.body.action == "batch" && req.body.added.length > 0)) {
(req.body.action == "insert") ? eventData.push(req.body.value) : eventData = req.body.added;
for (var i = 0; i < eventData.length; i++) {
var sdate = new Date(eventData[i].StartTime);
var edate = new Date(eventData[i].EndTime);
eventData[i].StartTime = (new Date(+sdate - (sdate.getTimezoneOffset() * 60000)));
eventData[i].EndTime = (new Date(+edate - (edate.getTimezoneOffset() * 60000)));
eventData[i].CreatedBy = //here I want to send the email to the database
dbo.collection('ScheduleData').insertOne(eventData[i]);
}
}
if (req.body.action == "update" || (req.body.action == "batch" && req.body.changed.length > 0)) {
(req.body.action == "update") ? eventData.push(req.body.value) : eventData = req.body.changed;
for (var i = 0; i < eventData.length; i++) {
delete eventData[i]._id;
var sdate = new Date(eventData[i].StartTime);
var edate = new Date(eventData[i].EndTime);
eventData[i].StartTime = (new Date(+sdate - (sdate.getTimezoneOffset() * 60000)));
eventData[i].EndTime = (new Date(+edate - (edate.getTimezoneOffset() * 60000)));
dbo.collection('ScheduleData').updateOne({ "Id": eventData[i].Id }, { $set: eventData[i] });
}
}
if (req.body.action == "remove" || (req.body.action == "batch" && req.body.deleted.length > 0)) {
(req.body.action == "remove") ? eventData.push({ Id: req.body.key }) : eventData = req.body.deleted;
for (var i = 0; i < eventData.length; i++) {
dbo.collection('ScheduleData').deleteOne({ "Id": eventData[i].Id });
}
}
res.send(req.body);
});
I am calling those endpoints in my schedule.component.ts:
private dataManager: DataManager = new DataManager({
url: 'http://localhost:8000/GetData',
crudUrl: 'http://localhost:8000/BatchData',
adaptor: new UrlAdaptor,
crossDomain: true
});
I am using the JWT token for user authorization at the moment, for example, this is my /profile endpoint:
router.get('/profile', authRequired, (req, res) => {
User.findOne({_id: req.decoded.userId}).select('username email').exec((err, user) =>{
if(err){
res.json({success: false, message: err});
} else {
if(!user){
res.json({success: false, message: 'User not found'});
} else {
res.json({success: true, user: user})
}
}
});
});
How can I access the users email to set the 'createdBy' field in the appointment?
If I console.log the token this way I just get undefined
This is the authRequired function in middleware.js file:
function authRequired(req, res, next) {
const token = req.get("authorization");
if (!token) {
res.json({ success: false, message: "No token provided" });
} else {
jwt.verify(token, config.secret, (err, decoded) => {
if (err) {
res.json({ success: false, message: "Token is invalid" + err });
} else {
req.decoded = decoded;
next();
}
});
}
}
module.exports = {
authRequired: authRequired
};
You are not running authRequired middleware on the POST /GetData route so the token is not extracted. Make sure you are also sending the token in the POST.
Update the route as you do in router.get('/profile', authRequired, (req, res) => { so you can get the decoded token.
app.post("/GetData", authRequired, (req, res) => {
var user = req.decoded; //decoded
...
});
I'm trying to save the userName of a user in express session. It saves the variable in session but it returns undefined on next request to the route. However, the problem is with POST route only.
With GET request, I can save session variable and it doesn't get destroyed on further requests. I think I must be doing something wrong. I tried save() method for POST but still it saves only first time and next time it is vanished.
Here's the code:
app.use(session({
secret: 'some secret',
resave: true,
saveUninitialized: true,
cookie: {
maxAge: 36000000,
httpOnly: false
},
}));
FOLLOWING GET ROUTE WORKS.
app.get("/test", function(req, res, next){
if(!req.session.name){
req.session.name = "vikas kumar";
} else {
console.log(req.session.name);
}
res.end();
});
app.use(function (req, res, next) {
var userName = req.session.userName;
// console.log(req.session.userName);
if(userName && userName != 'undefined'){
res.send({status: "success", value: userName});
} else {
if(req.path == '/checkIfLoggedIn'){
res.send({status: "error", message: "Session ended."});
} else {
next('route');
}
}
});
FOLLOWING ROUTE SAVES SESSION ONLY ONCE.
app.post('/getProfile', function (req, res, next) {
console.log("Session", req.session.userName, req.session.name);
if(typeof req.session.userName != 'undefined'){
var userName = req.session.userName;
} else {
var userName = req.body.userName;
}
connectionPool.getConnection(function (err, connection) {
if (err) {
res.send({status: "error", message: err});
} else {
connection.query("SELECT * FROM cs_chat.users WHERE username=?", [userName], function (err, rows, fields) {
if(rows.length==1){
// console.log(">>>", req.session.userName);
req.session.userName = userName;
req.session.save();
// console.log("<<<", req.session.userName);
next();
}else{
res.send({status: "error", message: "Sorry, you're not registered."});
}
connection.release();
});
}
});
}, function (req, res) {
connectionPool.getConnection(function (err, connection) {
if (err) {
res.send({status: "error", message: err});
} else {
req.session.username = req.body.userName;
req.session.save();
connection.query("SELECT usr.username, usr.name, tsn.sender, CASE WHEN tsn.unseen is not null THEN tsn.unseen ELSE 0 END as unseen, tsn.receiver FROM users usr LEFT JOIN (SELECT sender, receiver, SUM(CASE WHEN seen = 0 THEN 1 ELSE 0 END) AS unseen FROM messages WHERE receiver = ? GROUP BY sender , receiver) tsn ON usr.username = tsn.sender where usr.username!=?", [req.body.userName, req.body.userName], function (err, rows, fields) {
if(rows.length>0){
res.send({status: "success", values: rows});
}else{
res.send({status: "success", values: []});
}
connection.release();
});
}
});
});
Am I doing something wrong?
Since it is Javascript you should be checking quality with === instead of == and for better response time releasing the connection and then again connecting to it, is simply unnecessary, when you have the connection to connectionPool just query from it twice and then release the connection.
Here is the sample modified app.post().. request, this should work:
app.post('/getProfile', function (req, res, next) {
console.log("Session", req.session.userName, req.session.name);
var userName = (req.session.userName !== undefined) ? req.session.userName : req.body.userName;
connectionPool.getConnection(function (err, connection) {
if (err) {
res.send({ status: "error", message: err });
} else {
connection.query("SELECT * FROM cs_chat.users WHERE username=?", [userName], function (err, rows, fields) {
if (rows.length === 1) {
req.session.userName = userName;
req.session.save();
} else {
res.send({ status: "error", message: "Sorry, you're not registered." });
}
});
connection.query("SELECT usr.username, usr.name, tsn.sender, CASE WHEN tsn.unseen is not null THEN tsn.unseen ELSE 0 END as unseen, tsn.receiver FROM users usr LEFT JOIN (SELECT sender, receiver, SUM(CASE WHEN seen = 0 THEN 1 ELSE 0 END) AS unseen FROM messages WHERE receiver = ? GROUP BY sender , receiver) tsn ON usr.username = tsn.sender where usr.username!=?",
[req.body.userName, req.body.userName],
function (err, rows, fields) {
if (rows.length > 0) {
res.send({ status: "success", values: rows });
} else {
res.send({ status: "success", values: [] });
}
});
connection.release();
}
});
});