Similar question (but NOT a duplicate): How do i store request-level variables in node.js?
Consider this following code:
const express = require('express');
const app = express();
app.get('/', (req, res) => {
req.someVariable = "Hello";
res.send(req.someVariable + ' world!');
});
Where is req.someVariable stored? In a cookie? Does this apply for the user only or everyone? Also, what's the difference between these and storing them in sessions/cookies?
In addition to req being just a javascript object variable, stored in memory, do note express has a res.locals object variable that persist through the request/response cycle.
If you want to store any user information, you should be using the res.locals object so you do not accidentally overwrite other important objects.
res.locals
An object that contains response local variables scoped to the
request, and therefore available only to the view(s) rendered during
that request / response cycle (if any). Otherwise, this property is
identical to app.locals.
This property is useful for exposing request-level information such as the request path name, authenticated user, user settings, and
so on.
http://expressjs.com/en/5x/api.html#res.locals
app.use(function (req, res, next) {
res.locals.user = req.user
res.locals.authenticated = !req.user.anonymous
next()
})
Note: res.locals on it's own is not sent together with the response (e.g. res.send). It's only accessible in your nodejs app.
Cookies
Cookies are information bits that you want to send to the client's browser (stored in browser memory). The client can then send the cookie back to your nodejs app. These are different from req and res properties.
Cookie can store for example, an authentication token, which can be stored in the client's browser, and provided to the nodejs app on every request.
For security, you can use a httpOnly cookie which cannot be modified by browser javascript.
Related
I want to create a login system, using Node JS and ExpressJS. The user types their credentials, then the server checks these to see if they are valid. If they are valid, the server will redirect the user the home page and send along data, including the user's credentials (for further use). This is RESTful.
const app = require("express")();
const bodyParser = require('body-parser');
app.get("/login", function(req, res)
{
res.sendFile(__dirname + "/front-end/login.html");
});
app.post("/login",function(req, res)
{
var username = req.body.username;
var password = req.body.password;
//returns whether the credentials work
var credentialsPassed = checkCredentials(username,password);
if(credentialsPassed)
{
//redirect to home-page and pass along the user's credentials for further use
}
});
I already read How do I redirect in expressjs while passing some context?. The answer sends data in the url. However, I need to send the user's credentials, so it would be insecure to pass it in the URL. The other alternative is to use EJS (or something similar), but I would have to download a pretty big module just for this 1 task.
Is there any better way?
If you don't want the data to be passed in the URL you can add it to req.users or res.locals/req.locals.Definition:
[req.locals vs. res.locals vs. res.data vs. req.data vs. app.locals in Express middleware
Also in the link you passed they said you could save that data in req.session maybe that is the best way to solve your problem
I wanted to know if there is a way to share variables between 2 routes in expressJS without declaring it as a global. Consider I have the following routes:
exports.routeOne = (req,res) => {
var myVariable='this is the variable to be shared';
}
exports.routeTwo = (req,res) => {
//need to access myVariable here
}
How can this be done ?
===============
Note
This answer is answering the wrong question, but it might still be useful for others who also misinterpreted the question like I did, so I'm keeping it here for now.
===============
In order for the variable to exist it would have to first execute routeOne and then execute routeTwo. This is a pretty common scenario with express. To get the details on how this works read up on middleware (http://expressjs.com/en/guide/writing-middleware.html) and understand that each route is middleware.
The common pattern solution here is to add a new property to either the req or res object that stores your variable. Then you tell the route to call the next middleware. The next middleware has access to the same req and res so it also has access to the property and value that you just stored.
There is nothing wrong with this practice as most middleware does it. For example the body-parser middleware (https://www.npmjs.com/package/body-parser).
Here is an example of how your code might run:
routes.js
exports.routeOne = (req,res,next) => {
req.myVariable='this is the variable to be shared'
next()
}
exports.routeTwo = (req,res) => {
//need to access myVariable here
console.log(req.myVariable)
}
index.js
const express = require('express')
const routes = require('./routes.js)
const app = express()
app.use(routes.routeOne)
app.use(routes.routeTwo)
app.listen(3000)
One of the awesome things about NodeJS is that you can store state in variables. The process that runs your NodeJS server continues to run without restarting for each request that comes in. So any variables you store using GLOBAL.myVarName or variables that you store within the scope of a module (a single JavaScript file) will persist... until the process quits. The process could quit if the server goes down or if an Error or other exception is throw that is not caught. You can set up a process manager to keep it running, but your in memory variables are now lost.
I would recommend using variables that are scoped at a higher level for caching, but if the data is important it should be stored to and read from a database as needed.
Here is an example of your routes.js module. Any variable you declare outside of functions are scoped to this file. In other words, the variables are global to this file. You can read up more on that at https://nodejs.org/dist/latest-v8.x/docs/api/modules.html and https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures.
routes.js
let variableScopedToModule = 0
exports.routeOne = (req, res) {
variableScopedToModule++
}
exports.routeTwo = (req, res) {
console.log(variableScopedToModule)
}
If it is important that you never loose the variables state, and assuming you are not running the server on multiple processes for load balancing, then you could do something like this:
routes.js
const db = require('./my-db-controller')
let cachedValue
exports.routeOne = async (req, res) {
if (cachedValue === undefined) cachedValue = await db.getValue()
cachedValue++
db.setValue(cachedValue)
}
exports.routeTwo = (req, res) {
console.log(cachedValue)
}
This second solution is more complex because you'll need to understand promises as well as async and await. Also this solution will not work if you are using a load balencer unless you use something like Redis. Alternatively you can just read and write to the database for each request instead of using in memory caching.
For user-specific data that you want to persist from one request to the next, you can't just store data in simple server-side variables because server-side variables are freely shared among all users who make requests of your server.
The usual way to store server-side data that is user-specific is to use a session object. In a nutshell, when a user makes a request, some session middleware (which runs on every request) checks to see if a session cookie exists. If it does not, then one is created. The session cookie servers to uniquely identify that particular user when they make future requests.
Once you have a unique session cookie, the session middleware can create a session object that corresponds with that session cookie. Typically, there is a unique ID in the session cookie that servers as a lookup key for the session object.
Now, whenever that user makes a request of your server, the session middleware will look at the session cookie, get the encrypted session id out of it, decrypt the id, look up the session object that corresponds to that id and then make that session object available to your request handlers, usually in req.session. Your request handlers then have full access to the session object and can add, remove or modify your own properties on that session object.
express-session is common piece of middleware that is used for implementing sessions with nodejs/express. There are plenty of examples for how to use it in the documentation so I won't repeat that all here. Here's one such example in the doc.
By default, express-session uses a memory store (which just means the session objects are kept in memory). This can be fine for simple uses, but it has some limitations and express-session does not recommend it for production use. One major limitation of keeping the sessions in memory is that if the server crashes or restarts, all session data is lost. There are dozens of add-in object stores for express-session, most of which store data more durably such as in a database on disk.
I have a simple authentication system built on Passport.js on top of Node.js. I have a use case where I need to persist Organisation ID in the session which is to be updated on hitting of a particular route.
I did this using the middleware:
app.use('/switchOrganization',function(req, res, next) {
if(req.user) req.session.passport.user.activeOrg = 'my org';
next();
});
But this doesn't persist the data in other routes:
app.route('/someRoute').post(function(req,res){
console.log(req.session.passport.user);
});
It doesn't contains the 'activeOrg' value. Where I am going wrong?
The user object is deserialized into req.user in the deserializeUser function. This happens on each request. So if you make change to req.user in one of the route handlers, and expect it to be persisted for the route handlers that follow it, it'll only be the case for that particular request. If /someRoute is requested anew, it will not have the the changes you made in another route which wasn't invoked in the new request.
You should instead persist the changes to database so that when the deserializeUser function is called for the next request, it'll have your data from the beginning.
I am using redis sessionStore. And if I write to req.session, then data persists on redis store:
req.session.access_token = result.access_token;
req.session.refresh_token = result.refresh_token;
req.session.instance_url = result.instance_url;
Redis Screenshot
I'm checking and setting a couple of cookies in the middleware before hitting the route. After hitting the route, inside the handler, I'm trying to access the aforementioned set cookies but the response object has no accessor for these set cookies.
# similar to req.cookies.cookie_name to access cookies sent by the client
stored_value = res.cookies.cookie_name # this method doesn't exist
The response object exposes a getHeader method, using which I attached a simple cookie parser on response.getHeader('Set-Cookie') to the response object.
app.use (req, res, next) ->
#
# returns a hash of cookie_name: cookie_value,
# or cookie_value if cookie_name is sent as an argument
#
res.jit_cookies = (cookie_name) ->
cookies = {}
for cookie in this.getHeader('Set-Cookie')
tokens = cookie.split(';')[0].split('=')
cookies[tokens[0]] = tokens[1]
if cookie_name? then cookies[cookie_name] else cookies
next()
So now I can access the cookies I set anywhere I have access to the response object.
res.jit_cookies() # returns a hash of all cookies set
res.jit_cookies('lang') # returns the value of the 'lang' cookie
I'm using cookies so that the state of the response is bound to the response object which is later accessed in many places.
Is this okay to do? Are there other (and better) ways to track and access the same information that I'm trying to use cookies for?
There already is a cookie-parser middleware that parses cookies for you and puts them in req.cookies.
As far as accessing the req when you only have res, you can access res.req.
You need to use a middleware called: "cookieParser"
If you are using Express v3.X:
app.use(express.cookieParser());
instead if you are using 4.X you need to also import it and use it as follows:
var cookieParser = require('cookie-parser')
app.use(cookieParser())
Of course, for the second option you need to first install the package:
$ npm install cookie-parser
In that way you can get access of cookies like:
req.cookies // returns an object
req.cookies['yourCookieName']
I'm rather new to node, I have started writing a small app and am working on my user auth and profile. I'm using express, passport and ejs. I've got passport working and have my user redirecting to a profile page that requires additional data before the user begin's to use the application. My question is:
What's the proper way to update the user's session (created at passport.authentication) when a user updates their profile data? I would like to update the user session in order to hit it rather than the data base for basic user data.
If your using express you have middleware that looks like:
function (res, req, next){}
When you get session data you can add it to the req object.
function (res, req, next){
// get the session here...
req.session = session;
}
Then any other middleware will have access to the req.session object which will contain the user's session.