Setting Global / Local Vars - node.js

I'm just getting started with Node and I'm running into issues setting variables. In the example below, it appears the value of random will be the same for every user because it's being set on app start.
var random = math.Random();
app.post('/api/whatever/', function(req, res) {
console.log(random);
});
Using a local variable will mean that the value of random changes every time a post request is made:
app.post('/api/whatever/', function(req, res) {
var random = math.Random();
console.log(random);
});
What I'm trying to figure out is how to set the value of random once per user / session (i.e. the first time a user makes a call to /api/whatever). I have other configuration variables to set after the first request, so it may be better to just trigger an init() function. The problem would be the same though.

Your global variable could hold an object whose keys are session ID and values are whatever session-specific information you want - such as your random number.
To get the session ID, see this question: How can I find the session Id when using express / connect and a session store?

Use the express-session module:
npm install express-session
Here's an example:
...
var session = require('express-session');
app.use(session({secret: '1234567890QWERTY'}));
app.get('/api/whatever/', function(req, res) {
if(req.session.random) {
res.send('Your random key is: ' + req.session.random);
} else {
req.session.random = Math.random();
// Set anything else you want in req.session ...
}
});

Related

express-session: How to renew ssid but preserve data?

I use node.js and express.js to implement my web server.
I use express-session module (https://github.com/expressjs/session) to handle web sessions and connect-redis (https://github.com/tj/connect-redis) for session store. I believe it does not relate to the type of the store but in case you ask I told you.
After user login and doing some sensitive data changed, eg. change the password, I'd like to renew the ssid. So I use req.session.regenerate(). However, after the function call, all other session data lost. How can I preserve the session data after renewing the ssid?
What actual behaviour:
req.session.userId = 100;
req.session.regenerate(function(err) {
// will have a new session here
console.log(req.session.userId); // undefined
});
What I want:
req.session.userId = 100;
req.session.regenerate(function(err) {
// will have a new session here
console.log(req.session.userId); // 100
});
Below is what I have done. It works but is it the correct way to do that?
var sessionData = req.session;
req.session.regenerate(function(err) {
// will have a new session here
req.session = sessionData;
});
It cannot be done in current version 1.15.6. The feature will be added in the future.
https://github.com/expressjs/session/issues/425
It is a good workaround. Maybe better use Object.assign:
var sessionData = req.session;
req.session.regenerate((err) => {
Object.assign(req.session, sessionData);
});

Express.js unique var per request outside routing

In my express application I have a module called helpers thats is required in almost all my routes and modules. This module has a logger method that logs to fluentd (but that's unimportant). While building the data to log I'd like to add a unique identifier of the request, so that all the logs written for the same request have the same unique ID. Using a global var in the app entry point app.use doesn't work because this var would be overwritten every time a new request hits, so the global uuid will change would obviously change in case of high load or long running tasks. The res.locals is not available outside routing, so I can't use it for this matter. Is there a way to create a var that would be unique per request and available in every module or maybe a way to access the res.locals data outside routing? Thank you
EDIT
Maybe an example will help understand better the question.
Suppose I have a module called helpers.js like this:
let helpers = {};
helpers.log = (logData, logName) => {
fluentLogger.emit('', {
name: logName,
//uuid: the needed uuid,
message: logData
});
}
module.exports = helpers;
Now obviously I can do this in my app.js entry point:
app.use(function (req, res, next) {
res.locals.uuid = uuid.v4();
next();
});
and then in every loaded middleware module that requires helpers(adding a new param to the helpers.log method):
const helpers = require('helpers');
router.post('/', (req, res, next) => {
helpers.log('my log message', 'myLogName', res.locals.uuid);
next();
});
and this will normally work. But suppose a big or middle size project where there are hundreds of custom modules and models (not middlewares) and a module may require other modules that require other modules that require finally the helpers module. In this case I should pass the res.locals.uuid as a parameter to every method of every method so that I have it available in the logger method. Not a very good idea. Suppose I have a new module called dbmodel.js that is required in a middleware function:
const helpers = require('helpers');
let dbmodel = {};
dbmodel.getSomeData = (someParam) => {
//some logic
helpers.log('my log message', 'myLogName');
}
module.exports = dbmodel;
The dbmodel has no idea about the res.locals data if I don't pass it from the middleware, so the helpers.log method will also have no idea about this.
In PHP one would normally write a GLOBAL var in the application's entry point so a hypothetical logger function would have access to this global on every method request from whichever class of the application.
Hope this explanation will help :) Thank you
EDIT 2
The solution for this kind of problems is CLS. Thanks to #robertklep for the hint. A good slideshare explaining exactly the same problem (logger with unique ID) and explaining the CLS solutions can be found here: https://www.slideshare.net/isharabash/cls-and-asynclistener
I answered a very similar question here which will solve this problem.
I used to solve the problem the libraries node-uuid and continuation-local-storage. Take a look to the answer of this question and see if it helps:
NodeJS Express - Global Unique Request Id
And you want a bigger explanation, take a look here:
Express.js: Logging info with global unique request ID – Node.js
Yes you can do so by one method .
Every request comes to his routes pass that request inside the middleware.
Suppose you have
app.get('/', function(req, res) {
res.sendFile(path.join(public + "index.html"));
});
a request.
Place Middleware in it .and edit req field coming , in this way you will get the unique variable values for each request
check out this .
https://expressjs.com/en/guide/writing-middleware.html
Like this
var requestTime = function (req, res, next) {
req.requestTime = Date.now()
next()
}
app.use(requestTime)
app.get('/', function (req, res) {
var responseText = 'Hello World!<br>'
responseText += '<small>Requested at: ' + req.requestTime + '</small>'
res.send(responseText)
})
Here req.requestTime is unique for each request.

Node.js variables for current request only?

I am very new to Node.js, and I was wondering if that, except for session(), I could use a "storage" to store variables for the current request?
I have an API which is based on an Authorization header, and a pool of valid tokens stored in Redis.
Therefore I don't have a session and don't want to.
But I would like to store variables for further use during this request. For example, I would like to store the user_id corresponding to the token found in Redis, so that I can use it wherever I want.
If I do something like:
app = express();
app.user_id = 1;
Is it ok, or will my user_id become global to all requests handled by the app? (in short: is the app instanciated for each request handled by the server, or is it persistent?)
If this is not ok, how could I achieve something like this without sessions?
Thank you for any help :)
The app handles all requests, and would only be created once on startup, but req lives for only the lifetime of the request. Keep in mind that the req in Express is just an object, and as such, can be assigned values. So if you wanted to allow the controller to have access to some value (similar to sessions), you could do something like this:
var express = require('express');
var app = express();
// middleware that assigns a value '123' to 'req.user_id'
app.use(function(req, res, next) {
req.user_id = 123;
next();
});
// controller which responds with the 'req.user_id'
app.get('/hello', function(req, res){
res.send('req.user_id: ' + req.user_id); // responds with req.user_id: 123
});
app.listen(3000, function() {
console.log('Listening on port 3000');
});
In the above example, the middleware that I created assigns a value to the request, called user_id. This value lives for the life of the request. You could do a similar thing to assign a dynamic value to the req so that you can access it via your controllers.

NodeJS + session object in ALL views without passing it on all controller actions

I want my session to be available in all views (*.ejs) without having to pass it on every single action. My code is shown below, but the req.session object is always null here, even though in my "controllers" I can access a session object after an user has authenticated, by specifying:
req.session.whatever
My initialization code (that is currently executed on every single request (I double checked with a debug breakpoint) is:
var appendLocalsToUseInViews = function(req, res, next)
{
//append request and session to use directly in views and avoid passing around needless stuff
res.locals.request = req;
if(req.session != null && req.session.user != null)
{
res.locals.user = req.session.user;
}
next(null, req, res);
};
I register this function in the app setup preamble:
app.use(appendLocalsToUseInViews);
I have seen people use app.use methods and dynamicHelpers. I am using express 3, and it seems they are gone, deprecated from Express 2... But that does not seem to be the point, as the function is being called correctly on every single request. How to I access the Express session in this sort of pre-controller code?
Thanks!
SOLUTION thanks Jani Hartikainen:
I moved the code to after the session middleware is loaded and its working!!! Here is the new code.
app.use(express.cookieParser(appSecret));
app.use(express.session({ secret: appSecret }));
---->>>app.use(appendLocalsToUseInViews);
This should work but make sure your app.use for this is only after you have initialized your session middleware. If you have this before the initialization for the session middleware, it will be ran before it in the chain, and thus the data will not be available.

Not cookie based session management in node.js

I am looking for a non-cookie based session management in node.js, something like pass a parameter in the URL like &session_id=. It will know that a session has expired when a request comes with an session_id. I've looked at connect library, but it looks that it is cookie based only.
Warning
Passing the session id as a GET parameter is considered bad practice. Why? It is dangerous because people don't usually care about session id and they will probably publish/share links with their session ids inside.
It's also a problem because when a user clicks an external link on your web, and goes to another site, that new site will be able to see the session_id in the referrer link.
So I don't think it is a good idea. Cookies are more secure.
Have a look at: Session Hijacking
For every request you receive, you will get all of the client cookies accordingly.
You can also set client cookies in the response HTTP headers using "Set-Cookie."
Using a GET parameter is unsafe. Any user could accidently share their session ID, but if you want 100% security, I'd share session IDs via cookies, and I would use HTTPS to prevent snoopers from stealing cookies.
You can use localstorage or sessionStorage..
almost same as cookie
not a cookie
better than a cookie!
More info: https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Storage
It's very -very- easy to use... in Js for example:
<script>
// check if Storage is avaible
if(typeof(Storage)!=="undefined") {
// Save data to local storage (no exiparion date)
localStorage.setItem("name_always", "bxx");
// Save data to the current session (removes when the tab is closed)
sessionStorage.setItem("name_now", "bxx");
} else {
// No Storage support...
}
// Access to stored data
alert( "For only now, my name is: " + sessionStorage.getItem("name_now"));
alert( "Every day, my name is: " + localStorage.getItem("name_always"));
</script>
Tags: javascript html5 local-storage session-storage
You can use sessions with a store in node.js. For example, you have express application and want to use session like system in your webapp. You can use connect-mongo module for this. This will let you store your session in db. In your app.js
var express = require('express'),
, mongoStore = require('connect-mongo')(express);
var app = express();
app.configure('all', function () {
app.use(express.session({
secret: "terces",
cookie: { maxAge: 24 * 60 * 60 * 1000 },
store: new mongoStore({
url: your_db_url
})
}));
app.use(function(req, res, next) {
res.locals.session = req.session;
next();
});
});
With basic code above, you have session in express that you can use it in your controllers and views directly. In your controller;
app.post('/blog/create/?', function(req, res, next) {
if (!req.session.user) {
next("You need to login in order to create blog!");
}
});
In your view, you can use session.user in order to generate profile menu for example.

Resources