I am trying to pass a Boolean value from one file to another in a Node.js application.
auth.js
const express = require("express");
const router = express.Router();
var isLoggedIn = false;
router.get("/", (req, res) => {
res.render("pages/auth");
console.log(isLoggedIn);
});
router.post("/", (req, res) => {
if (req.body.password == "Secret") {
isLoggedIn = true;
res.redirect('/home');
} else {
res.send("<h1 align='center'>Wrong password</h1>");
}
console.log(isLoggedIn);
});
module.exports = {
auth: router,
isLoggedIn: isLoggedIn,
};
If the password is correct, the value of isLoggedIn should be true but if I import it in another file, it turns false.
How do I fix this?
I don't mind installing another package.
You are creating and exporting the object at the moment the server starts up - and at the moment the server starts up (that is, that the top-level code here runs), the value assigned to isLoggedIn is false.
While you could kind of fix it by exporting a function that, when called, returns the value of the variable:
module.exports = {
auth: router,
getIsLoggedIn: () => isLoggedIn,
};
A more fundamental problem is that the variable is being set for the lifetime of the server being online, for all users. If, for example, user A logs in, unregistered person B who accesses the website from some other browser halfway around the world shouldn't be seen as logged in. The isLoggedIn variable should be ditched entirely (unless the logic you want is that once one person logs in, the server sees everyone hitting your endpoints as being logged in - which sounds very unusual).
Use something like session variables instead, so each person accessing the website has separate settable and retrievable state.
Related
When working on middleware's in Node JS, i have implemented a code on if age>=18 user can access the website otherwise not but when i type query like localhost:3000/?age=12 it works but localhost:3000/?age="12" it doesn't works anyone knew why it happens and how to resolve it
code:
const express = require('express')
const app = express()
const port = 3000
// middleware
// req,res we need to modify so it is there
// next is a function it will proceed when route is called
const reqFilter=(req,res,next)=>{
console.log('reqFilter');
// we have to call next otherwise it will keep loading in browaer
// eg:-> if age is older then 18 user can access page
if(req.query.age<18){
res.send('Please Confirm You are over 18')
}
else if(!req.query.age){
res.send("please put down age")
}
else{
next();
}
}
// using the middleware
app.use(reqFilter)
app.get('/', (req, res) => {
res.send("welcome to homepage")
})
app.get('/users', (req, res) => {
res.send("welcome to users page")
})
app.listen(port, () => console.log(`Example app listening on port ${port}!`))
From express docs: https://expressjs.com/en/api.html.
As req.query’s shape is based on user-controlled input, all properties and values in this object are untrusted and should be validated before trusting. For example, req.query.foo.toString() may fail in multiple ways, for example, foo may not be there or may not be a string, and toString may not be a function and instead of a string or other user-input.
You're comparing the query parameter to the Number 18, You need to check the type of the query. You can do so with if (typeof req.query.age == 'string') and perhaps convert the "18" to a Number.
You can do so by adding + like that: +req.query.age
What is the best way to call a function on many but not all requests in a node express app? (An example would be a function which checks if the user is currently logged in)
What I did is to define a module exporting a checkLogin(...) function and to call this function on each corresponding api-request. E.g.:
Module auth:
module.exports = {
checkLogin: function(req, res, next) {
if (req.session.hasOwnProperty('user')) {
//if the user is logged in we pass through
next();
} else if (req.cookies.user == undefined || req.cookies.pass == undefined) {
res.render('login', { title: 'Login' });
} else {
User.checkLogin(req.cookies.user, req.cookies.pass, true, function(o) {
if (o != null) {
req.session.user = o;
next();
} else {
res.render('login', { title: 'Login' });
return;
}
});
}
}
};
Routes for /index:
//...
var auth = require('../middlewares/auth.js');
//...
router.get('/index', auth.checkLogin, function(req, res) {
//if we passed the auth.checkLogin step we render the index page
res.render('index', {
title: 'Index',
udata: req.session.user
});
});
In another route file:
//...
var auth = require('../middlewares/auth.js');
//...
router.get('/user/someAPICall', auth.checkLogin, function(req, res) {
...
});
Is this the way to go or are there better ways to do that? I could define a middleware function which I could include using app.use(function(){..}) in each route. The problem is that every request for this route would go through this function which is not what I want.
Routers (http://expressjs.com/en/guide/routing.html) are a great way to design your application. You could think of your URL paths as namespaces, and create a router for the namespace that requires user authentication.
Most likely your main /index page won't require immediate redirecting to login, since it's used for presentation purposes; but if required, then just include the auth.checkLogin as you did above.
For everything else where you need your user to be authenticated (e.g. everything under /user/*), you'd better create a scoped router
const router = express.Router();
router.use(auth.checkLogin);
router.get('/someAPICall', fn1, fn2);
router.get('/someOtherAPICall', fn3, fn4);
and then in your parent router or main app, just include the router:
app.use('/user', router);
which is just like defining:
app.use('/user/someAPICall', [auth.checkLogin, fn1, fn2]);
app.use('/user/someOtherAPICall', [auth.checkLogin, fn3, fn3]);
This gives you the advantage of creating modular route handlers - which makes them easier to adjust, reuse, etc. - and at the same time will keep auth.checkLogin, although always executed when the router is entered, just for the paths defined by the router.
In short, the approach would be: "execute function on all routes inside the router, but not on all the app requests".
If you cannot redesign your routes in this way, then yes, you'll always need to include auth.checkLogin in handlers list for the paths you only want to use.
I want to verify that a user has a role which allows him/her to use an endpoint in my API. Usually I would go about doing so by taking the userId sent as part of a JWT and do a lookup on the DB to see what the user's role is. It would happen inside an API call and would look something like this:
var userId = getUserIdFromJwt();
app.models.User.findOne({_id: userId}, function (err, user) {
...check if user is in role...
});
Now I want to try and move that code to a piece of middleware, which would look like this:
exports.isUserInRole = function(app, allowableRoles) {
var userId = getUserIdFromJwt();
app.models.User.findOne({_id: userId}, function (error, user) {
if (error) {
return res.status(500).json(error);
}
return function (req, res, next) {
if(_.includes(allowableRoles, user.Role)) {
next();
} else {
return res.status(401).json({"error": "User not in role"});
}
}
});
};
The middleware would be implemented like this:
const allowableRoles = ['admin', 'implementor'];
app.get('/getStuff/', isUserInRole(app, allowableRoles), function (req, res) {
... do stuff if user is in role ...
});
At this point I am running into a problem where the app.models.User value is always undefined.
I do not understand why app.models.User is undefined at this point as I can access it within the anonymous function inside the get call.
How would I go about about access the DB from within my middleware if I cannot send it app.models.User?
For reference, I am using Mongoose and exposing it to my app in the server.js from which I access the a MongoDB db.
I think you're problem is that you are trying to get models before they are actually initialized, as you are binding the app to the parameters on initialization of the app.
So in your main app file, I would do module.exports = app; and then in your middleware file, simply include the app by doing var app = require('./path/to/app');. Then remove the app from the middleware. You might end up with something like this:
var app = require('./path/to/app');
exports.isUserInRole = function(allowableRoles) {};
And in your route change it to this:
const allowableRoles = ['admin', 'implementor'];
app.get('/getStuff/', isUserInRole(allowableRoles), function (req, res) {}
And lastly in your app file, add the app to the exports:
module.exports = app;
EDIT:
If you're using Mongoose, you can also do something more simple like this:
var mongoose = require('mongoose');
var User = mongoose.model('User');
My first guess would be b/c you are actually calling the function instead of just passing it in. Additionally, you're not actually passing in middleware. Middleware functions look like
function(req,res,next){}
Additionally, you probably want to leverage sessions instead of hitting the database on each request
I am building an app with nodejs and expressjs. For authentication and user roles I am using respectively passport and connect-roles.
I have built the connect-roles object as shown in here: https://github.com/ForbesLindesay/connect-roles
Like so:
var user = new ConnectRoles()
This is in my app.js. Then I have exported such object like so:
exports.user = user;
However, if I import this object with require I see a strange behavior, please check code below:
var express = require('express');
var router = express.Router();
var user = require('../app.js');
//1
console.log(user);
/* GET users listing. */
router.get('/', function(req, res) {
//2
console.log(user);
res.send('respond with a resource');
});
module.exports = router;
The object is undefined in case 1 and is as it should be in case 2. Basically, I get 2 different objects depending if I am inside or outside the router.get function. I have been debugging this for half day, but I can't figure out what is happening.
The issue is that this object should be injected to provide roles management like so:
router.get('/', user.is("admin"), function(req, res) {
Of course this gives an error since user outside the get function object is undefined. The error is "cannot call method is of undefined".
The problem you have is most likely a cyclic dependency. Your router file requires your app.js file and your app.js file requires your router. What this means is that your router file gets a partially initialised object, that is only later filled in. The best way around this is to factor out the roles into a separate module, then require it from both places. i.e. have an authorisation.js file that looks like:
var ConnectRoles = require('connect-roles');
var user = new ConnectRoles();
// set up all the authorisation rules here
module.exports = user;
Then in both app.js and the router file, do var user = require('./authorisation.js');
This is a general problem whenever you create cyclic dependencies, and is not specific to connect-roles.
I can't see how user would be undefined there... but I can suggest that you use
module.exports = user
As this will give you the object:
{ functionList: [],
failureHandler: [Function: defaultFailureHandler],
async: false,
userProperty: 'user' }
Rather than:
{ user:
{ functionList: [],
failureHandler: [Function: defaultFailureHandler],
async: false,
userProperty: 'user' } }
With your current implementation you could do:
router.get('/', user.user.is("admin"), function(req, res) {
If this does not solve your issue you may need to provide app.js in it's entirety.
I'm using sessions and cookies to authenticate the users. I would like to check for users having a cookie and if so i will set the sessions variables.
So basicly what i do is :
Check if sessions variables exist
If not, check if user has cookie
If he has a cookie, I compare the value in my database.
If everything's ok, I set up the session.
Now i'd like to have that process into a module so i don't have to paste that code into each routes of my site.
Let's say I've put all that code in a middleware route located at routes/middleware/check_auth.js.
How do I export this module so I can check in my route page if the user has auth or not, something like :
//routes/index.js
var check_auth = require('./middleware/check_auth');
module.exports = function(app){
app.get('/', check_auth, function(req, res){
if(variable_from_check_auth == true){
res.render('index_with_auth');
}else{
res.render('index_without_auth');
}
});
};
Btw, I'm not sure if it's the right way to do or if I simply have to :
Call the module on each routes.
Check for some sessions variables before rendering.
If someone could help me!
You can just export your middleware as simple as this(assuming you are using express session handler and cookie parser):
var userModel = require('./user');
module.exports = function check_auth(res, req, next) {
if (!res.session) {
req.send(401);
return;
}
userModel.isAuthenticated(req.session.id, function (result) {
if (!result) {
req.send(401);
return;
});
next();
});
};