I am trying to use redis to store sessions with express-session. Here is the code:
//Imports
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const session = require('express-session');
const logger = require('morgan');
//Connect to Redis
const redis = require('redis');
let RedisStore = require('connect-redis')(session);
let redisClient = redis.createClient();
redisClient.connect();
redisClient.on('connect', () => console.log('Connected to Redis..'));
app.use(
session({
store: new RedisStore({ client: redisClient }),
saveUninitialized: false,
secret: 'keyboard cat',
resave: false,
})
);
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(logger('dev'));
app.get('/', function (req, res) {
var body = '';
console.log(req.session);
if (req.session.views) {
++req.session.views;
} else {
req.session.views = 1;
body += '<p>First time visiting? view this page in several browsers :)</p>';
}
res.send(
body + '<p>viewed <strong>' + req.session.views + '</strong> times.</p>'
);
});
app.listen(3000, () => console.log('App is listening on port 3000'));
Whenever I start my application, it freezes. I have checked the redis-cli and pinged it with the response 'PONG'. redis-server is starting just fine. Whenever I remove the following lines:
redisClient.connect();
redisClient.on('connect', () => console.log('Connected to Redis..'));
the app crashes whenever I hit the "/" route. But if I had those lines in, the app just hangs there and doesn't do anything. I checked the docs here and they said you need to connect before any command:
https://github.com/redis/node-redis/blob/HEAD/docs/v3-to-v4.md#no-auto-connect
And the code I'm running is right from the connect-redis npm page:
https://www.npmjs.com/package/connect-redis
I'm not sure why the server is freezing. It works fine if I remove store from the session so it's definitely something to do with redis but on the node side. The redis server is running fine on the localhost. Any suggestions?
**UPDATE
I checked the connect-redis repo issues and I found that someone else is having the same problem as me. The problem will be resolved in the next commit:
https://github.com/tj/connect-redis/issues/336
This is currently a known issue. Currently connect-redis is not compatible with the latest version of node redis.
https://github.com/tj/connect-redis/issues/336
Add the following to your client to fix this issue until patched:
const client = createClient({
legacyMode: true
});
Related
I know there are already some questions with same problems. But none of them solved my issue.
I use reactJS as my frontend code and expressJS as my server code.
My problem is, each time express gets request, it regenerates a different sessionID.
As the solution I found here, Express change session every request, that secure must be set to false if you want to prevent sessionID from resetting for every request.
The code below is my session setting in app.js
app.use(
session({
resave:false,
saveUninitialized:false,
secret:process.env.redis_secret_key,
cookie:{
maxAge:3600,
httpOnly:true,
/**
* for production code:
* secure:true
*/
secure:false
},
store:new RedisClient({createdClientRedis})
})
);
As you see, secure is set to false, but!
the code which I used to set cookie and redis.get shows me different sessionID.
code of cookie.js
const express = require('express');
module.exports={
setCookie:function(res,req,id){
res.cookie('user',req.sessionID);
},
removeCookie:function(res){
res.clearCookie('user',{path:'/'});
}
}
result:
redis code:
getRedis:function(req){
console.log("get redis "+req.sessionID);
return new Promise((resolve,reject)=>{
//some redis.get code
})
},
result:
Of course, getRedis function generates different sessionID for every request too.. and I cannot get value from redis database.
And the react code which I use to send a fetch request to server already has credentials setting.
export function chatRoomFetch(type,requestBody){
return fetch(`//localhost:8000/chat/${type}`,{
method:'POST',
credentials:'include',
headers:{
'Accept':'application/json',
'Content-Type':'application/json'
},
body:JSON.stringify(requestBody)
}).then((response)=>{
return response.json();
});
};
What am I doing wrong?
This is my entire express.js app.js code
//main javascript file for nodejs. server
const express = require('express');
const session = require('express-session');
const app = express();
const port = 8000;
const cors =require('cors');
const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser');
const chatRouter = require('./router/chatRouter.js');
const authRouter = require('./router/authRouter.js');
const redis = require ('./redis/redis');
const { RedisClient } = require('redis');
const redisStore= require('connect-redis')(session);
require('dotenv').config();
//cors setting
app.use(cors({
origin:'http://localhost:8081',
credentials:true
}));
app.use(express.urlencoded({extended: true}));
app.use(express.json());
app.use(cookieParser());
//redis
const createdClientRedis = redis.createRedisClient();
app.use(
session({
resave:false,
name:'user',
saveUninitialized:false,
secret:process.env.redis_secret_key,
cookie:{
maxAge:3600,
httpOnly:true,
/**
* for production code:
* secure:true
*/
secure:false
},
store:new RedisClient({createdClientRedis})
})
);
//Routers
app.use('/chat',chatRouter);
app.use('/auth',authRouter);
app.listen(port, () => {
console.log(`Example app listening on port ${port}!`)
});
I am facing an issue with handling session using latest version of Express, Node.js.
My requirement is to store users email id in /login route, and need to get that email id thought out
all routes like /home. But email id is not printing in /home route with my current code. Your help is much appreciate.
My demo code is here
var express = require('express');
var app = express();
var cookieParser = require('cookie-parser');
var session = require('express-session');
var RedisStore = require('connect-redis')(session);
app.set('port',process.env.PORT || 3000);
app.use(cookieParser());
app.use(session({
resave: false,
saveUninitialized: false,
store: new RedisStore({
host: 'localhost',
port: 6379
}),
secret: 'some string/hash secret'
}));
var counter=0;
app.get('/login', function(request, response){
//adding some value to request.session
request.session.email = 'jak#amt.in';
console.log('sessionID', request.sessionID)
response.send('email: '+request.session.email);
});
app.get('/home', function (request, response) {
console.log('home login', request.session.email); // Email not priting here
console.log('sessionID - home', request.sessionID); // Session ID is showing
response.send('home');
});
if (!module.parent) {
console.info('Listening ', process.env.PORT || 5000);
app.listen(process.env.PORT || 5000);
}
module.exports = app;
I am getting following error
"ReplyError: ERR wrong number of arguments for 'set' command
at parseError (/home/dibeesh/obpnode6/testproject/node_modules/redis/node_modules/redis-parser/lib/parser.js:161:12)
at parseType (/home/dibeesh/obpnode6/testproject/node_modules/redis/node_modules/redis-parser/lib/parser.js:222:14)"
Make sure your redis server is running when you run your app.
Initially this error message started appearing very infrequently, but started to appear more regularly and now appears 4/5 times I run my application.
I'm handling my session store with Mongo and as I understand it, the TTL index is used to make the session data expire.
/home/dan/dev/audio-wave/node_modules/connect-mongo/lib/connect-mongo.js:161
throw new Error('Error setting TTL index on collection : ' + s
^
Error: Error setting TTL index on collection : sessions
at /home/dan/dev/audio-wave/node_modules/connect-mongo/lib/connect-mongo.js:161:23
at /home/dan/dev/audio-wave/node_modules/connect-mongo/node_modules/mongodb/lib/mongodb/db.js:1404:28
at /home/dan/dev/audio-wave/node_modules/connect-mongo/node_modules/mongodb/lib/mongodb/db.js:1542:30
at /home/dan/dev/audio-wave/node_modules/connect-mongo/node_modules/mongodb/lib/mongodb/cursor.js:159:22
at commandHandler (/home/dan/dev/audio-wave/node_modules/connect-mongo/node_modules/mongodb/lib/mongodb/cursor.js:678:48)
at Db._executeQueryCommand (/home/dan/dev/audio-wave/node_modules/connect-mongo/node_modules/mongodb/lib/mongodb/db.js:1802:12)
at Cursor.nextObject (/home/dan/dev/audio-wave/node_modules/connect-mongo/node_modules/mongodb/lib/mongodb/cursor.js:729:13)
at Cursor.toArray (/home/dan/dev/audio-wave/node_modules/connect-mongo/node_modules/mongodb/lib/mongodb/cursor.js:158:10)
at Cursor.toArray (/home/dan/dev/audio-wave/node_modules/connect-mongo/node_modules/mongodb/lib/mongodb/scope.js:10:20)
at /home/dan/dev/audio-wave/node_modules/connect-mongo/node_modules/mongodb/lib/mongodb/db.js:1541:65
Here's the code that ties it together
var sessionStore = new MongoStore({ db: 'audio-drop' })
, cookieParser = express.cookieParser('waytoblue')
, SessionSockets = require('session.socket.io')
, sockets = new SessionSockets(io, sessionStore, cookieParser);
app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.use(express.favicon());
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.static(path.join(__dirname, 'public')));
app.use(express.logger('dev'));
app.use(cookieParser);
app.use(express.session({
store: sessionStore
}));
According to db.version() from the Mongo shell, I'm running 2.4.9 and I'm using version 0.4.0 of connect-mongo.
There seem to be a number of people who've hit this issue, but it seems that most of them resolved to being credential issues, my local mongo is not secured with authentication, so this can't be the problem. Any ideas?
As I said in your comment, essentially Express is receiving connections before the session store is fully connected. The solution is to wait for the connection to occur before allowing your application to start listening.
You can avoid this problem by using a callback on MongoStore creation, or passing in an already active connection.
Example using connect-mongo's Callback
var sessionStore = new MongoStore({ url: 'someConnectionUrl', db: 'audio-drop' }, function(e) {
var cookieParser = express.cookieParser('waytoblue');
app.use(cookieParser);
app.use(express.session({
store: sessionStore
}));
app.listen();
});
Simple Mongoose Example
var mongoose = require('mongoose');
mongoose.connect('localhost', function(e) {
// If error connecting
if(e) throw e;
var sessionStore = new MongoStore({ mongoose_connection: mongoose.connection }),
cookieParser = express.cookieParser('waytoblue');
app.use(cookieParser);
app.use(express.session({
store: sessionStore
}));
app.listen();
});
Upgrade to connect-mongo version 0.8.0 which worked for me.
angular fullstack example
It´s just to encapsulate all the other stuff inside the mongoose.connect callback function
See my server/app.js
/**
* Main application file
*/
'use strict';
// Set default node environment to development
process.env.NODE_ENV = process.env.NODE_ENV || 'development';
var express = require('express');
var mongoose = require('mongoose');
var config = require('./config/environment');
// Connect to database
mongoose.connect(config.mongo.uri, config.mongo.options , function(e){
// Populate DB with sample data
if(config.seedDB) { require('./config/seed'); }
// Setup server
var app = express();
var server = require('http').createServer(app);
var socketio = require('socket.io')(server, {
serveClient: (config.env === 'production') ? false : true,
path: '/socket.io-client'
});
require('./config/socketio')(socketio);
require('./config/express')(app);
require('./routes')(app);
// Start server
server.listen(config.port, config.ip, function () {
console.log('Express server listening on %d, in %s mode', config.port, app.get('env'));
});
// Expose app
exports = module.exports = app;
});
Hope it helps!!
I'm trying get access to session data in express so I thought I would try declaring a connect-redis session store when configuring express. However, I cannot see why this doesn't work:
var express = require('express');
var http = require('http');
var RedisStore = require('connect-redis')(express);
var app = express();
app.set('port', process.env.PORT || 3000);
app.use(express.bodyParser());
app.use(express.cookieParser());
app.use(express.session({ secret: "keyboard cat", store: new RedisStore }));
//app.use(express.session({ secret: "keyboard cat" }));
app.use(app.router);
app.get('/', function(req, res){
console.log('/');
req.session.items = [ 'apple', 'orange' ];
res.end('items configured');
});
app.get('/items', function(req, res){
console.log('/items: ', req.session.items);
var s = JSON.stringify(req.session.items);
res.end('items: ' + s);
});
var server = http.createServer(app).listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
});
The '/' route simply configures items with the session.
The '/items' route displays the list of items in the session.
It works using the standard expressjs session store.
It doesn't work using connect-redis (req.session is undefined)
I'm assuming the redis store will be instantiated and destroyed as the app loads/unloads (or do I need it running outside of node/express app?)
Any ideas?
req.session will be undefined if RedisStore can't connect to your Redis server. So it's either not running, or it's not running on the default location that RedisStore is looking for it (127.0.0.1:6379).
In case of the latter, you can configure the location using the options argument to the RedisStore constructor.
Give this a try.
var express = require('express');
var redis = require("redis");
var session = require('express-session');
var redisStore = require('connect-redis')(session);
var bodyParser = require('body-parser');
var client = redis.createClient();
var app = express();
app.set('views', __dirname + '/views');
app.engine('html', require('ejs').renderFile);
app.use(session({
secret: 'ssshhhhh',
// create new redis store.
store: new redisStore({ host: 'localhost', port: 6379, client: client,ttl : 260}),
saveUninitialized: false,
resave: false
}));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.get('/',function(req,res){
// create new session object.
if(req.session.key) {
// if email key is sent redirect.
res.redirect('/admin');
} else {
// else go to home page.
res.render('index.html');
}
});
app.post('/login',function(req,res){
// when user login set the key to redis.
req.session.key=req.body.email;
res.end('done');
});
app.get('/logout',function(req,res){
req.session.destroy(function(err){
if(err){
console.log(err);
} else {
res.redirect('/');
}
});
});
app.listen(3000,function(){
console.log("App Started on PORT 3000");
});
link : https://codeforgeek.com/2015/07/using-redis-to-handle-session-in-node-js/
You should invoke RedisStore constructor (with ())
app.use(express.session({ secret: "keyboard cat", store: new RedisStore()}));
I'm a Node-beginner and have the following problem. I use express, socket.io and passport as well as passport.socketio and a MongoStore.
I need to authenticate socket.io with passport (I use passport.socketio for this), but the handshake is always unauthorized even after successfull login. Here is my code so far:
var http = require('http')
var socketio = require('socket.io')
var express = require('express')
var stylus = require('stylus')
var passport = require('passport')
var passportSocketIo = require('passport.socketio')
var LocalStrategy = require('passport-local').Strategy
var mongo = require('mongoskin')
var MongoStore = require('connect-mongo')(express)
var DB = mongo.db('mongo://127.0.0.1/accounts', {safe:false})
DB.bind('accounts')
DB.bind('SessionStore')
SessionStore = new MongoStore({ db: 'SessionStore' })
var app = express()
app.configure(function () {
app.set('views', __dirname + '/views')
app.set('view engine', 'jade')
app.use(express.cookieParser())
app.use(express.bodyParser())
app.use(express.session({
secret: 'somekey',
store: SessionStore
}));
app.use(passport.initialize())
app.use(passport.session())
app.use(app.router)
})
Here is where I login:
app.post('/login', passport.authenticate('local', { successRedirect: '/',
failureRedirect: '/login_failed',
failureFlash: false }))
And here I try to access a page ('/content'), for which I need authorization:
app.get('/content', ensureAuthenticated, function(req, res){
res.render('content', { user: req.user })
})
var server = http.createServer(app).listen(5050)
var io = socketio.listen(server)
io.set('authorization', passportSocketIo.authorize({
cookieParser: express.cookieParser,
key: 'express.sid',
secret: 'somekey',
store: SessionStore,
fail: function(data, accept) {
accept(null, false);
},
success: function(data, accept) {
accept(null, true);
}
}))
But if a client now tries to access '/content', the server always responds 'handshake unauthorized':
// on client side
socket = io.connect('http://localhost:5050');
// on server side
io.sockets.on( 'connection', function( socket ) {
console.log(socket.handshake.user._id)
}
-> handshake unauthorized
Does anyone know what I do wrong here?
Yes that's an issue known since two years and not resolve yet :
https://github.com/LearnBoost/socket.io/issues/545
As koenigsbier said in this github issue :
In my client side I had var socket =
io.connect('http://localhost:8080'); and it's works only if you put
localhost:8080 in your browser.
I changed it by var socket = io.connect('http://127.0.0.1:8080');
and now it works with localhost:8080 and 127.0.0.1:8080 in your
browser.
It's clearly a bug, why socket.io should accept address mapping just
in one way? localhost is localhost and is the same as 127.0.0.1
On client side, try to put 127.0.0.1 instead of localhost
You need to use:
key: 'connect.sid',
instead of
key: 'express.sid',
for the key. Check out the cookie in your browser, you won't see express.sid, but connect.sid will have a value. The only other difference that I see between yours and my working example is I set a var to express.cookieParser and then use that both in app config and in io.set authorization.
var cookieParser = express.cookieParser();