How do I get sessions working with Node.js, express#2.0.0 and mongodb? I'm now trying to use connect-mongo like this:
var config = require('../config'),
express = require('express'),
MongoStore = require('connect-mongo'),
server = express.createServer();
server.configure(function() {
server.use(express.logger());
server.use(express.methodOverride());
server.use(express.static(config.staticPath));
server.use(express.bodyParser());
server.use(express.cookieParser());
server.use(express.session({
store: new MongoStore({
db: config.db
}),
secret: config.salt
}));
});
server.configure('development', function() {
server.use(express.errorHandler({
dumpExceptions: true,
showStack: true
}));
});
server.configure('production', function() {
server.use(express.errorHandler());
});
server.set('views', __dirname + '/../views');
server.set('view engine', 'jade');
server.listen(config.port);
I'm then, in a server.get callback trying to use
req.session.test = 'hello';
to store that value in the session, but it's not stored between the requests.
It probobly takes something more that this to store session values, how? Is there a better documented module than connect-mongo?
Take a look at this series from DailyJS. It uses MongoDB and session management
http://dailyjs.com/tags.html#lmawa
I am not experienced with Node.js or Express, so I cannot immediately see what's wrong with your approach. However, I have made Express use MongoDB to store sessions for flash messages and other session stuff.
You can see my source code for a simple URL shortener here (that actually makes the URLs pretty long at the moment - it was just an exercise ;)). I use the session to store a list of URLs that the current user has shortened.
It is not pretty, but I know it works.
Related
I am using Expressjs and the Auth0 API for authentication and ReactJs for client side.
Because of the limitations of the Auth0 API (spoke with their team) I am sending updated user details to my backend and then using app.set() to be able to use the req.body in another route.
I need to call the app.patch() route automatically after the app.post() route has been hit.
The end goal is that the users data will be updated and shown client side.
const express = require('express');
const cors = require('cors');
const path = require('path');
const app = express();
require('dotenv').config()
const { auth } = require("express-openid-connect");
app.use(express.json());
app.use(cors());
app.use(express.static(path.join(__dirname, 'build')));
app.use(
auth({
issuerBaseURL: process.env.AUTH0_ISSUER_BASE_URL,
baseURL: process.env.BASE_URL,
clientID: process.env.AUTH0_CLIENT_ID,
secret: process.env.SESSION_SECRET,
authRequired: false,
auth0Logout: true,
})
);
app.get('/', async (req, res) => {
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});
app.get('/api', async (req, res) => {
const stripe = require('stripe')(`${process.env.REACT_APP_Stripe_Live}`);
const invoice = await stripe.invoices.list({
limit: 3,
});
res.json(invoice);
});
app.post('/updateuser', (req, ) => {
app.set('data', req.body);
})
app.patch(`https://${process.env.AUTH0_ISSUER_BASE_URL}/api/v2/users/:id`,(req,res) => {
let val = app.get('data');
req.params = {id: val.id};
console.log(req.params);
})
app.listen(process.env.PORT || 8080, () => {
console.log(`Server listening on 8080`);
});
I'd suggest you just take the code from inside of app.patch() and make it into a reusable function. Then it can be called from either the app.patch() route directly or from your other route that wants to do the same funtionality. Just decide what interface for that function will work for both, make it a separate function and then you can call it from both places.
For some reason (which I don't really understand, but seems to happen to lots of people), people forget that the code inside of routes can also be put into functions and shared just like any other Javascript code. I guess people seems to think of a route as a fixed unit by itself and forget that it can still be broken down into components and those components shared with other code.
Warning. On another point. This comment of yours sounds very wrong:
and then using app.set() to be able to use the req.body in another route
req.body belongs to one particular user. app.set() is global to your server (all user's requests access it). So, you're trying to store temporary state for one single user in essentially a global. That means that multiple user's request that happen to be in the process of doing something similar will trounce/overwrite each other's data. Or worse, one user's data will accidentally become some other user's data. You cannot program a multi-user server this way at all.
The usual way around this is to either 1) redesign the process so you don't have to save state on the server (stateless operations are generally better, if possible) or 2) Use a user-specific session (like with express-session) and save the temporary state in the user's session. Then, it is saved separately for each user and one user's state won't overwrite anothers.
If this usage of app.set() was to solve the original problem of executing a .patch() route, then the problem is solved by just calling a shared function and passing the req.body data directly to that shared function. Then, you don't have to stuff it away somewhere so a later route can use it. You just execute the functionality you want and pass it the desired data.
I’m building an API for a SPA built with Angular 2, for this app I have a stand alone API and than an Angular 2 app. So they are on built on two separate node.js servers. I’m using node.js and express along with 'express-connection' and 'mysql' modules to build a secure API to handle login and registration with JWT’s (json web tokens), along with other tasks of course. So I’ve successfully built this API so I can access data with my Angular 2 app via a URL. I can use the URL ’localhost:3000/data’ to access a json data object from my Angular 2 app running on 'localhost:3001/'. However, I also need the API to have access to this data object (an array of users) once the data becomes available. What is the best way to approach/accomplish this task? The only way I can think of now is to have a setTimeout function that waits for the app to load than uses an http get to grab the data from the url. There must be a cleaner way of accomplishing this task. Heres some code I have working, basically a simple node server running express. I'm somewhat new with building API's and Angular 2 concepts so any help is greatly appreciated.
app.js
/** Dependencies **/
var logger = require('morgan'),
cors = require('cors'),
http = require('http'),
express = require('express'),
errorhandler = require('errorhandler'),
dotenv = require('dotenv'),
bodyParser = require('body-parser');
/** Setup **/
var app = express();
dotenv.load();
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(cors());
app.use(function(err, req, res, next) {
if (err.name === 'StatusError') {
res.send(err.status, err.message);
} else {
next(err);
}
});
if (process.env.NODE_ENV === 'development') {
app.use(logger('dev'));
app.use(errorhandler())
}
/** Requires **/
require('./config/sql.js')(app);
require('./config/routes.js')(app);
/** Port **/
var port = process.env.PORT || 3001;
http.createServer(app).listen(port, function (err) {
console.log('listening in http://localhost:' + port);
});
routes.js
// routes.js
module.exports = function(app) {
var query = require('./query.js')(app);
app.get('/data', function(req, res) {
query.getData(req,res);
});
};
sql.js
var connection = require('express-myconnection');
var mysql = require('mysql');
module.exports = function(app){
app.use(
connection(mysql,{
host : 'localhost',
user : 'root',
password: ‘password’,
port : 3306,
database: ‘my_project’
}, 'request')
);
};
query.js
// DB Queries
module.exports = function(app){
return {
getData: function(req, res) {
req.getConnection(function(err,connection){
connection.query('SELECT * FROM users',function(err,rows){
// console.log("success: ", rows);
res.json(rows);
});
});
}
}
};
user.js
setTimeout(function(){
// http.get function to call to API and grab data and create variable
},500);
// this is where I need an array of users that I get from a mysql database for login and registration logic
var users = [];
I'm not sure I got why you need the Angular code to talk to a different UrL but I would write the server code to take the requests from Angular and then internally reach out to the other API to get the data required. Basically use the node server to act like a proxy to reach the other API.
jfriend00 is right in his comment, this is a question of asynchronous calls.
You are looking for the initial requests to kick off the following: Frontend Request > NodeJS API > Database Query
And the response to fulfill and return promises to create a response chain in the reverse order: Database Response > NodeJS API > Frontend Response
You are probably looking for the angular function $http.get with .then() to perform your frontend calls. But you also need an asynchronous function to request the data from within the API or a database instance, then provide it on an endpoint that the frontend can consume. For that you need a promise or callback in your server-side code as listed in jfriend00's comment.
Consider working on just your NodeJS API until you can achieve the response and requests you need, and build out your frontend with Angular later. The users.js file is a fine endpoint to start on.
Here's my initial config:
var session = require('express-session');
var cookieParser = require('cookie-parser');
app.use(session({
saveUninitialized: true,
resave: false,
genid: function(req) {
return Services.misc.generateUUID()
},
secret: secret.toString()
}));
app.use(cookieParser(secret));
Then in my controller (it's routed through a dead simple router to a controller, which then renders appropriate actions based on a Rails-like naming convention) I'll do something like this:
var TestController = {
noaction: function(req, res) {
var locals = {
billy: 'the goat'
}
console.log('req session'.red, req.session);
res.cookie('test_cookie', 'Wu Tang Clan');
this.services.render.view(req, res, this, 200, locals);
}
module.exports = TestController;
Note that this.services.render.view is just a service so that I don't have to write res.render('./app/controllers' + controller + '/' + action)
Note the res.cookie line in the controller (docs on express.js). That's what the official docs say to do and in fact, it's then set in the browser:
However, the line above res.cookie is a log and I would imagine we'd have test_cookie in it, but:
All I get is a standard blank cookie every time, even though it's set browser-side and supposedly sending.
My question is: How do I properly set and receive cookies in Express 4?
Here's the answer: Every time nodemon restarts the server to propagate code changes, the sessions are cleared.
Your code seems to be ok, as dsp_099 said, it is probably the nodemon.
The express-session saves the data in-memory, so when you restart your server (with nodemon automatically) all the memory data is reseted.
I you wanna persist the session data even if node is restarted, may i suggest you use redis-session (Redis Database)
How can I maintain my SESSIONS in Node.js?
For example, I want to store UserID in SESSION using Node.js. How can I do that in Node.js? And can I use that Node.js SESSION in PHP too?
I want the following in Node.js:
<?php $_SESSION['user'] = $userId; ?>
First install the session package
npm install express-session --save
Initialization of the session on your server page
var express = require('express');
var session = require('express-session');
var app = express();
app.use(session({secret: 'ssshhhhh', saveUninitialized: true, resave: true}));
Store session
sess = req.session;
var user_id = 1;
sess.user_id = user_id;
Access the session
sess = req.session;
sess.user_id
Let me divide your question in two parts.
How can I maintain my SESSIONS in Node.js?
Answer: Use express-session middleware for maintaining SESSIONS
Can I use that a Node.js SESSION in PHP too?
Answer:
Yes, you can use that session in PHP too, but keep in mind you have to store that session in the database.
ExpressJS has official session middleware, and it is also the current de-facto standard web framework for Node.js.
If you wish to implement session support on your own, this is how the implementation is normally done, upon every request:
Check if the cookie contains a session ID
If not, create a session object that is either stored in memory, on file, or in a database (or a combination of those), and set the session id in the response cookie to match this object's identifier.
If the cookie does contain a session ID, locate the session object by the ID.
Provide the obtained/created object from step 1 as the persisted session object for the request.
You will also have to implement some timeout mechanism, so that after a while the session objects are deleted, at least from memory.
You could use the express-session middleware.
Combine it with connect-redis or connect-mongo to store your sessions inside a database and save memory if memory is valuable to you (like in a cloud setup).
express-sessions (npm)
If you store it in, say, MongoDB, use the PHP MongoDB driver to pick it up from there.
You don't need to do it by yourself. There are some amazing modules in Node.js that handle this kind of things for you.
You can use session middleware from Express.js, as suggested before.
However, I'd recommend you to use Passport.js. This module does the authentication part for you, has a lot of strategies that you could integrate in your website (log in with Facebook, Google, Twitter, etc.), and deals with all the session stuff automatically, using serializeUser() and deserializeUser() functions whenever you need to.
You can take a look at this here, within the "Sessions" section: Configure Passport.js
Session that gives access/permission to view a user's area, as well as it's a credential, so we can use it over the application.
I used jsonwebtoken to make a token which will has the user's details with time after a successful login attempt by the user. I stored it in Redis, and it can be used for a pre-declared time limit.
To maintain a session is now older, and you should try with using JWT token. It is very effective and easy. But still to maintain the session in Node.js:
In your Express.js configuration:
var cookieParser = require('cookie-parser');
var session = require('express-session');
app.use(cookieParser());
app.use(session({
secret: 'secret',
resave: true,
saveUninitialized: true,
rolling: true,
cookie: {
path: '/',
maxAge: 60000 * 1000
},
name: 'SID'
}));
Store session after Login:
var session = req.session;
if (user) {
session.user = user._id;
session.save();
console.log(session);
}
Check Session from middleware:
var session = req.session;
if (session.user) {
req.userid = session.user;
next();
} else {
return res.status(401).send({
code: 401,
message: Constant.authentication_fails
});
}
Follow the below steps:
npm install express-session --save
Write the below code:
var express = require('express');
var session = require('express-session');
var app = express();
app.use(session({secret: 'your secret key', saveUninitialized: true, resave: true}));
var userId = 1234;
app.get('/', function (req, res, next) {
req.session.userId = userId;
});
Storing a session in Node.js is fairly easy but you need to understands its step, you could handle this manually, also you can use few NPM modules. Passport can help you to authenticate and login and store the session i would recommend you to read its documentation, Passport allow you to authenticate user with different other platform like Google, github many more.
If you are going to use passport use these below NPM module
Passport
Passport Local
Express-flash
Express-session
2 -Import these modules in your main app.js:
const flash = require('express-flash')
const session = require('express-session')
const passport = require('passport')
app.use(session({
secret:'secret',
resave:false,
saveUninitialized:false
}))
app.use(flash())
app.use(passport.initialize())
app.use(passport.session())
3- Create the passport.js file. You can name anything. So basic understanding behind this is that you have to check the valid user coming from your input form, and you have to compare the email id with your model. If it is valid, check the password and then return the user. Once that is done, serialize and deserialize your user data to store in the session..
I would recommend to check this part in the documentation for more clear understanding: Overview
const localStrategy = require('passport-local').Strategy
const bycrypt = require('bcrypt')
const User = require('../model/User')
const initalize = function(passport) {
const auth = async(email, password, done) => {
try {
const user = await User.findOne({email:email})
if(!user) {
throw new Error("Incorrect Email ..!")
}
const match = await bycrypt.compare(password, user.password)
if(!match) {
throw new Error('Incorrect Password..!')
}
return done(null, user)
}
catch (error) {
console.log(error)
done(null,false,error)
}
}
passport.use(new localStrategy({usernameField:'email'}, auth))
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
}
module.exports = initalize
4 - Now go to your login router and use the below code
const passport = require('passport')
require('../passport/passport')(passport)
routes.get('/signin', (req,res) => {
res.render('signin', {
pageTitle: 'sign in'
})
})
routes.post('/signin', passport.authenticate('local', {
successRedirect: '/welcome',
failureRedirect: '/',
failureFlash: true
}))
You can use sessions in Node.js by using the 'express-session' package in Node.js.
You have to install express and express-session in your application:
const express = require('express');
const session = require('express-session');
const app = express();
"secret" is used for the cookie, and we have to add some secret for managing a session.
"request" we use as a request variable as we use $_SESSION in PHP.
var sess;
app.get('/',function(req,res){ // Get request from the app side
sess = req.session;
sess.email; // Equivalent to $_SESSION['email'] in PHP.
sess.username; // Equivalent to $_SESSION['username'] in PHP.
});
Here is full documentation in Code for Geek about the session in Node.js if you want to learn in detail about the session in Node.js.
You can handle the session in two ways.
Using express-session
Using JWT web token and handle your own session (token-based session handling).
I think token-based session handling is more important rather than using express-session. You will get a problem when you scale your server and also a problem with some single device login situation.
For checking I have a token-based session handling Node.js folder structure. You can check it, and it may be helpful.
Taking the simple example from Union, I am wondering where I can put configuration code that usually goes in app.configure, like passport.js:
app.configure(function() {
// Initialize Passport! Also use passport.session() middleware, to support
// persistent login sessions (recommended).
app.use(passport.initialize());
app.use(passport.session());
});
Any ideas? server and router don't accept use().
Union appears to use the before collection for this:
var server = union.createServer({
before: [
connect.session({ secret: 'keyboard cat' }), // for `passport.session()`
passport.initialize(),
passport.session(),
// etc.
]
});
From the "API" documentation:
#option before {Array}
The `before` value is an array of middlewares, which are used to route and serve incoming
requests. For instance, in the example, `favicon` is a middleware which handles requests
for `/favicon.ico`.
Union supports connect middlewares via the before property, as previously mentioned by others. However, union does not handle application configuration; flatiron does. The api, however, is significantly different from express.
For example, configuring an application may look something like this:
var path = require('path'),
flatiron = require('flatiron'),
app = flatiron.app,
plugins = flatiron.plugins,
connect = require('connect'), // most connect middlewares work with flatiron ootb
passport = require('passport');
// Use flatiron's http plugin (not the same as a middleware!)
app.use(plugins.http);
// configuration consists of key/value pairs, not of function blocks associated with
// certain "environments".
// Here's *a* way you can handle environment-based configs; there are others!
app.config.file(path.resolve(
__dirname,
'config',
(process.env.NODE_ENV || 'config') + '.json'
));
// Use our config to set the secret
app.http.before.push(connect.session({
secret: app.config.get('secret') || 'keyboard cat' //default
}))
app.http.before.push(passport.initialize());
app.http.before.push(passport.session());
I haven't tried running this example (I'm sure there are more details here) but hopefully this gives you an idea.
I just built a wrapper to integrate Passport.js with Flatiron.js.
https://npmjs.org/package/flatiron-passport
https://github.com/travist/flatiron-passport
Please read the README.md on how to use it and apply it to your application.
I have tested it on LocalStrategy, but it should work for other strategies.
Please let me know otherwise.