I am currently trying to create a client-side reroute for users that are invalid. The server validates if the user has access to the current page and if not it returns {data: 'invalid'} in the success callback of the ajax call I check this value with the following:
if (data.status === 'invalid') {
window.location.href = domain + '/login';
return false;
}
This works sometimes but other times I receive the following browser alert message:
RequestAbortedError: Request aborted
I have attempted to swap out window.location.href with window.location.replace() and top.location.href but neither resolved the issue. I can see that the server is processing the information correctly and returning {data: 'invalid'} but as soon as it tries to run the line window.location.href I receive this error. I have an image below if it helps.
When "OK" is clicked the page does redirect to the appropriate page. The end result is happening as expected but I cannot resolve the error.
UPDATE INCLUDING SERVER SIDE CODE
function authentication (req, res, next) {
console.log('entered');
if (typeof req.rsaConPortal.email !== 'undefined') { // Check if session exists
console.log('passed 1');
User.findOne({ "user.email": req.rsaConPortal.email, "user.status”: req.resConPortal.status}, function (err, user) {
if (!user) {
console.log('failed 2');
req.rsaConPortal.reset();
res.send({status: 'invalid'});
} else {
console.log('passed 2');
req.rsaConPortal.email = user.user.email;
req.rsaConPortal.id = user._id;
req.rsaConPortal.status = user.user.status;
next();
}
});
} else {
console.log('failed 1');
res.send({status: 'invalid'});
}
}
app.get('/api/savedApp/', authentication, function(req, res) {
if (req.rsaConPortal.status !== 'registered') {
res.send({status: 'invalid'});
} else {
User.find({ "_id": req.rsaConPortal.id }, {
profile: 1, documents: 1 }, function(err, user) {
if (err) throw err;
res.send(user);
});
}
});
Is there a better way to authenticate my users? I am using Mozilla's Client-Sessions npm package
The logs on the server are logging "Passed1" and "Passed2". It is sending the client "Invalid" based off the status inside the get call.
Based on reading further about express and a few comments I have received on this question I have decided to re-think my approach and look for a better alternative which I am happy to say I have found in express.Router. I was able to create an authentication function to determine if the user is authorized and handle the business logic of whether to let the user pass or send them back to the login. Then I created a route for each page that I have that takes the business logic a step further based on the users status and either lets them pass or sends them back to login.
Thanks to everyone who looked into this and provided comments.
var router = express.Router();
app.use(router);
var authenticate = function(req, res, next) {
if (req.rsaConPortal !== undefined) {
if (req.rsaConPortal.email !== undefined) { // Check if session exists
// lookup the user in the DB by pulling their email from the session
User.findOne({ "user.email": req.rsaConPortal.email, "user.password": req.rsaConPortal.passport }, function (err, user) {
if (!user) {
// if the user isn't found in the DB, reset the session info and
// redirect the user to the login page
req.rsaConPortal.reset();
req.rsaConPortal.email = '';
req.rsaConPortal.passport = '';
req.rsaConPortal.id = '';
req.rsaConPortal.status = '';
res.redirect('../login');
} else {
req.rsaConPortal.email = user.user.email;
req.rsaConPortal.passport = user.user.password;
req.rsaConPortal.id = user._id + '';
req.rsaConPortal.status = user.user.status;
next();
}
});
} else {
res.redirect('../login');
}
} else {
res.redirect('../login');
}
};
router.get(['/','/create_warranty','/help','/marketing_assets','my_documents','profile'], authenticate, function(req, res, next) {
if (req.rsaConPortal.status !== 'approved') {
res.redirect('../login');
} else {
next();
}
});
Related
I'm new in node.js...
I would create a chat app for school project but i have some problems with node module named "express"..
Error is in res.redirect('/');
var app = express();
var sess;
app.use(session({
secret: 'secret',
resave: true,
saveUninitialized: true
}));
app.get('/auth', function (req, res) {
var type = req.query.type;
sess = req.session;
if (type === "login") {
if (sess.loggedin) {
return res.redirect('/');
} else {
res.sendFile(__dirname + "/views/login.html");
}
}
});
app.post('/auth', function (req, res) {
var type = req.query.type;
sess = req.session;
if (type === "login") {
var login = req.body.login;
var password = req.body.password;
if (login === "" || password === "") {
res.send('You need to fill all inputs!');
res.end();
} else {
mysql query {
if (results.length > 0) {
res.send('Logged In');
sess.loggedin = true;
sess.username = results[0].username;
/* ERROR! --> return res.redirect('/'); <-- ERROR! */
} else {
res.send('Incorrect Username and/or Password!');
res.end();
}
res.end();
});
}
}
});
I watched youtube videos and readed forums but i didn't find the solution...
It will be nice if you can help me :)
It is because you have already sent a response with res.send('Logged In'). An HTTP Request is always a single request and a single response. The snippet below is taken from your code to show what happens.
res.send('Logged In'); // <-- Sends a response
res.redirect('/'); // <-- Sends another response in form of redirect.
The send methods sends a string as a response, which the client will receive. So now the headers for the response are already set and cannot send another response.
And sending a message and then redirecting doesn't make a lot of sense. You wouldn't have time to read the message because you are navigating to a different page. Lose the res.send and see what happens.
This is something,that really confuses. me. Let us suppose you have a REST API where you want the user to logout. After login out,the jwt(json web token) should be destroyed,so the user can not have access to the server's resources(ie menu,dishes etc).
In my case the user can logout,but he/she can still perform all the requests(get dishes,post and delete),until the token is valid. Here is my code.
verify.js
var User = require('../models/user');
var jwt = require('jsonwebtoken'); // used to create, sign, and verify tokens
var config = require('../config.js');
exports.getToken = function (user) {
return jwt.sign(user, config.secretKey, {
expiresIn: 3600
});
};
exports.verifyOrdinaryUser = function (req, res, next) {
// check header or url parameters or post parameters for token
var token = req.body.token || req.query.token || req.headers['x-access-token'];
// decode token
if (token) {
// verifies secret and checks exp
jwt.verify(token, config.secretKey, function (err, decoded) {
if (err) {
var err = new Error('You are not authenticated!');
err.status = 401;
return next(err);
} else {
// if everything is good, save to request for use in other routes
req.decoded = decoded;
next();
}
});
} else {
// if there is no token
// return an error
var err = new Error('No token provided!');
err.status = 403;
return next(err);
}
};
I am invalidating the token after a period of 1 hour.
And users.js where I set all the routes with their tasks. ie localhost:3000/users/login,localhost:3000/users/register and localhost:3000/users/logout. So.
var express = require('express');
var router = express.Router();
var passport = require('passport');
var User = require('../models/user');
var Verify = require('./verify');
/* GET users listing. */
router.get('/', function(req, res, next) {
res.send('respond with a resource');
});
router.post('/register', function(req, res) {
User.register(new User({ username : req.body.username }),
req.body.password, function(err, user) {
if (err) {
return res.status(500).json({err: err});
}
passport.authenticate('local')(req, res, function () {
return res.status(200).json({status: 'Registration Successful!'});
});
});
});
router.post('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) {
return next(err);
}
if (!user) {
return res.status(401).json(
err: info
});
}
req.logIn(user, function(err) {
if (err) {
return res.status(500).json({
err: 'Could not log in user'
});
}
var token = Verify.getToken(user);
res.status(200).json({
status: 'Login successful!',
success: true,
token: token
});
});
})(req,res,next);
});
router.get('/logout', function (req, res) {
req.logout();
res.status(200).json({
status: 'Bye!'
});
});
module.exports = router;
It seems that the logout method req.logout,doesn't work:(. Any ideas?
Thanks,
Theo.
You cannot log out a user that has a valid token if all the data is on the client side. You would need to store some state on the server to distinguish between users that you explicitly logged out and those that you didn't and check this state every time. If all of the data is entirely in the JWT token then you can't do anything to make it invalid (other than changing your secret that would invalidate all of the tokens, not just this one).
You actually discovered the main disadvantage of using authentication based entirely on the data that is included in the token itself. Those tokens cannot be invalidated. Once they're out then must be assumed to be active. You could only ask the client to forget it, but the client cannot be trusted to do that.
In theory you might have a fast data store like Redis where you keep all of the valid tokens and remove tokens from there to force logout, and check this storage on every request to know who is still logged in and who is not, but if you do that then you might store the session data in Redis in the first place and give only some random keys to that data store to the clients.
JWT is designed to be stateless. This means that all the information needed is contained in the token itself.
As the token has already been created, logout will have no effect on the validity of this.
This leaves you needing to keep a list of 'invalidated' tokens, which means you have once more introduced state.
If you are only concerned about subsequent users on the same machine, you could delete the token on logout, thus preserving the statelessness, but this will not protect against cases where the token has been captured.
I have a form on client-side which is sending data to server through AJAX in my Express app. I want to show some responses to the user when there are errors or the message sent successfully.
This code represents an error message when the message cannot be sent. The specific div in my handlebars template looks like this:
<div class="form-validation-error" style="{{formValidationError}}">ERROR: Message cannot be sent!</div>
Which is turned off by CSS default:
.form-validation-error {
display: none;
}
In my routes/contact.js I have a router.post block which is handling the message sending:
router.post('/', (req, res, next) => {
if(req.body.firstname.length === 0 || !req.body.firstname.match(/\D+/igm)) {
var validateFirstname = false;
} else {
var validateFirstname = true;
};
if(req.body.captcha.length === 0 || !req.body.captcha.match(/^kettő|ketto|two$/igm)) {
var validateCaptcha = false;
} else {
var validateCaptcha = true;
};
if(validateFirstname === true && validateCaptcha === true) {
console.log('SUCCESS: Form validated! The Nodemailer script will be here!');
} else {
console.log('ERROR: Form not validated!');
const formValidationErrorTrue = 'display: block;'; // -> How can I achieve this!??
res.send({formValidationError: 'display: block;'}); // -> Or this!??
};
});
After this block, I have a router.get template rendering part:
router.get('/', (req, res, next) => {
fsAsync((err, data) => {
if(err) {
res.render('404', {
title: 'Error 404'
});
}
const contact = data[2].contact;
res.render('contact', {
title: 'Contact',
data: contact,
formValidationError: formValidationErrorTrue // -> How can I achieve this!??
});
});
});
My question is, how can I share variables between router.post and router.get?
You could create a method and call that one in both get and post routes. I would encapsulate all logic in a controller instead of directly in your route. Perhaps you could also solve this using middleware (google express middleware) but I usually see that being used for authentication or error logging.
(Sorry for the short answer. I am typing on my phone)
I have a website that is accessing a local node.js server (that accesses a mongolab database), but when I use a front-end function to request a user JSON object, the mongo database returns nothing. (JSON.parse() finds an unexpected end of data at line 1 col 1)
Here is the front-end function that requests the user data by email and password:
function requestUser(email, password) {
xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", "http://localhost:8888/getUser/" + email + "/" + password, true);
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
user = JSON.parse(xmlhttp.responseText);
console.log(user);
}
}
xmlhttp.send();
}
Here is the node.js express server (back-end):
var http = require("http"),
mongojs = require("mongojs"),
express = require('express'),
cors = require('cors'),
fs = require("fs"),
url = require("url");
app = express();
app.use(cors());
var uri = "mongodb://<dbuser>:<dbpassword>#ds036698.mongolab.com:36698/alirodatabase";
var db = mongojs(uri, ["Papers", "Users"]);
app.get('/getUser/:email/:passwd', function(req, res, next) {
var users = db.Users.find({"email": req.params.email,
"password": req.params.passwd});
user = users.toArray[0];
res.json(user);
});
app.listen(8888, function() {
console.log('CORS-enabled web server listening on port 8888');
});
EDIT 1:
app.get('/getUser/:email/:passwd', function(req, res, next) {
var user = db.Users.findOne({
"email": req.params.email,
"password": req.params.passwd
}, function(err, doc) {
if (err) {
res.json({error: 'error retrieving the JSON user' });
}
else {
res.json(doc);
}
});
});
I added async functionality to the nodeserver, but now I am receiving the err: "error retrieving the JSON user". Is this a problem that could be solved by hosting my own database and not using mongolab?
You need to look at the docs for mongojs (https://github.com/mafintosh/mongojs). You're not using callbacks at all. The functions don't return values because it's Javascript/Node.js where things like to be async. So you have to use callbacks to handle the results. The idea is "find these documents" and then some time later when it actually gets the documents "do something with the documents".
app.get('/getUser/:email/:passwd', function(req, res, next) {
var users = db.Users.find({
"email": req.params.email,
"password": req.params.passwd
}, function(err, docs) {
if (err) {
//handle the error
res.json({error: ':(' });
}
else {
docs.toArray(function(err, users) {
if (err) {
//handle the error
res.json({error: ':(' });
}
else {
res.json(users[0]);
}
});
}
});
});
Lastly, I'd recommend using findOne rather than find. Then you won't need to use toArray to get a single document because it's returned as a single document in the first callback.
I am trying to inject a session value into the request so i can use it on different situation on my app. What i am doing is calling a function by giving the id to search for a user into database and return me the name of that specific user. The issue i am facing is when i try to declare the session, it looks like is not working or the callback is not letting this new value out.
Let me show you my code example for an better idea:
The middleware
var express = require('express');
var session = require('express-session');
var router = express.Router();
var userSession = require('../../helpers/user/userSession');
router.use(function(req, res, next){
if (req.method == "GET") {
if (!req.user) {
req.session.username = '';
}else{
var sess = userSession.findUser(req.user, function(err, user){
if (user) {
console.log(user); //It contains the value i need
req.session.username = user; // Supposed to inject the user value to the username session variable.
};
console.log(req.session.username); //it works until here, out of this function not anymore.
});
console.log(req.session.username); //the req.session.username is empty now
};
return next();
}else{
return next();
}
});
Check if user exist
var mongoose = require('mongoose');
var User = mongoose.model('database')
module.exports = {
findUser: function(user, callback){
User.findOne({ 'unq_id' : user }, function(err, user){
if (err) {
console.log('Error: ' +err);
return callback(err, false);
};
if (user) {
//console.log(user);
return callback(null, user.user_collection.firstname);
}else{
return callback(err, false);
};
});
}
}
One idea is to give to that sess variable the value of user, but it appears very difficult since is asynchronous call. I am sure some of might have run into this issue.
How can i get around this? any suggestion will be much appreciated.
How about this?
router.use(function(req, res, next){
if (req.method == "GET") {
if (!req.user) {
req.session.username = '';
next();
} else {
userSession.findUser(req.user, function(err, user){
if (user) {
req.session.username = user;
};
next();
});
}
} else {
next();
}
});
That way it won't go to the next middleware until after the username has been retrieved.