socket.io passport session undefinded - node.js

I want to use
req.user.id
inside
io.sockets.on('connection', module.exports = function(socket){}
so I tried to using this line
socket.request.client.user
like that on my
io.socket
io.sockets.on('connection', module.exports = function(socket,client,req){
connections.push(socket);
app.use(session({ secret: 'keyboard cat',resave: true, saveUninitialized:true})); // session secret
app.use(passport.initialize());
app.use(passport.session()); // persistent login sessions
console.log('connected: %s socket connected -session',socket.request.client.user ,connections.length);
but i get undefined on console
that's are my full code full code
var authController = require('./app/controllers/authcontroller.js');
var auth = require('./app/routes/auth.js');
var express = require('express')
var app = express()
var passport = require('passport')
var session = require('express-session')
var bodyParser = require('body-parser')
var env = require('dotenv').load()
var exphbs = require('express-handlebars')
app.use(session({secret: 'ssshhhhh'}));
app.use(passport.initialize())
app.use(passport.session())
var server = require('http').createServer(app);
var io = require('socket.io').listen(server);
var mysql = require('mysql');
var connection = mysql.createConnection({
host: 'localhost',
database: 'db_users',
user: 'root',
password: '',
});
users = [];
connections = [];
app.use('/cssFiles', express.static('/opt/lampp/htdocs/x/regtest/using-passport-with-sequelize-and-mysql-master/app/routes/assets'));
//For BodyParser
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
// For Passport
app.use(session({ secret: 'keyboard cat',resave: true, saveUninitialized:true})); // session secret
app.use(passport.initialize());
app.use(passport.session()); // persistent login sessions
//passport.authenticate('local-signin');
//For Handlebars
app.set('views', './app/views')
app.engine('hbs', exphbs({extname: '.hbs'}));
app.set('view engine', '.hbs');
app.get('/', function(req, res){
console.log('idddddd',req.sessionID);
res.send('Welcome to Passport with Sequelize');
});
//Models
var models = require("./app/models");
//Routes
var authRoute = require('./app/routes/auth.js')(app,passport);
//load passport strategies
require('./app/config/passport/passport.js')(passport,models.user);
//Sync Database
models.sequelize.sync().then(function(){
console.log('Nice! Database looks fine')
}).catch(function(err){
console.log(err,"Something went wrong with the Database Update!")
});
server.listen(process.env.PORT || 5000, function(err){
if(!err)
console.log("Site is live"); else console.log(err)
});
console.log('Server running...');
app.get('/', function(req, res){
res.sendFile('/opt/lampp/htdocs/x/regtest/using-passport-with-sequelize-and-mysql-master/app/routes/page.html');
});
//connection.connect();
io.sockets.on('connection', module.exports = function(socket,client,req){
//con
connections.push(socket);
//app.use(session);
app.use(session({ secret: 'keyboard cat',resave: true, saveUninitialized:true})); // session secret
app.use(passport.initialize());
app.use(passport.session()); // persistent login sessions
console.log('connected: %s socket connected session',socket.request.client.user ,connections.length);

req.user is only available in express middleware unfortunately. You'll have to use something like https://www.npmjs.com/package/passport.socketio if you want to access passports user info.
You will have to use some sort of persistent store as well such as redis or mongodb

Related

How to render route before rendering static files in node js?

I want to render app.use('/', callback function) before rendering the static files from public folder.
Basically I am doing the authentication before accessing the website, so once it gets authenticated it should load the index.html (static file) from the public folder.
How should i do it?
I am using W3ID from IBM to authenticate the site.
const express = require('express');
const session = require('express-session');
const passport = require('passport');
const WebAppStrategy = require("ibmcloud-appid").WebAppStrategy;
const CALLBACK_URL = "public/index.html";
var path = require('path');
var bodyParser = require('body-parser');
var port = process.env.VCAP_APP_PORT || 8080;
var mongoose = require('mongoose');
//var MongoStore = require('connect-mongo')(session);
const app = express();
// mongodb connection
mongoose.connect("mongodb://admin:admin123#ds261430.mlab.com:61430/events");
var db = mongoose.connection;
// mongo error
db.on('error', console.error.bind(console, 'connection error:'));
// parse incoming requests
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.static(path.join(__dirname, 'public')));
app.set('views', path.join(__dirname, 'views'));
// Set view engine as EJS
app.engine('html', require('ejs').renderFile);
app.set('view engine', 'html');
// include routes
app.use(session({
secret: "123456",
resave: true,
saveUninitialized: true
}));
app.use(passport.initialize());
app.use(passport.session());
passport.use(new WebAppStrategy({
tenantId: "73585f35-8d9c-4f6f-9ab2-d07ca0c1d371",
clientId: "863fce57-a717-4586-b8a2-0bf221ef4e68",
secret: "MzkxMTMxMWMtNmYxNi00ZjNhLWFiNzctZjFlM2NkMDM1ZTkz",
oauthServerUrl: "https://appid-oauth.eu-gb.bluemix.net/oauth/v3/73585f35-8d9c-4f6f-9ab2-d07ca0c1d371",
redirectUri: "https://csi.eu-gb.mybluemix.net/" + CALLBACK_URL
}));
passport.serializeUser(function(user, cb) {
cb(null, user);
});
passport.deserializeUser(function(obj, cb) {
cb(null, obj);
});
app.get(CALLBACK_URL, passport.authenticate(WebAppStrategy.STRATEGY_NAME));
app.use('/',passport.authenticate(WebAppStrategy.STRATEGY_NAME), function(req, res) {`enter code here`
// do your authentication
});
// listen on port 8080
app.listen(port);
You can do this by just putting your app.use('/',...) above the app.use('/',express.static('...')).
Or
You can do this by passing option {index:false} to express.static like
app.use('/',express.static('path here',{index:false}));
This option will set express.static to not send the index.html by default.

CANNOT GET / in Node app

I've checked the other related questions and can't pinpoint what's causing the issue (don't have a lot of experience here). I'm trying to launch this app locally basically with its default settings (other than some Twilio keys), have the dependencies installed, mongo is running, but localhost:5000 returns CANNOT GET /.
> node server.js
listening on port 5000
server.js:
// modules =================================================
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var http = require('http').Server(app);
var io = require('socket.io')(http); //real-time chat
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var cookieParser = require('cookie-parser');
// configuration ===========================================
// public folder for images, css,...
app.use(express.static(__dirname + '/public'))
// config files
// database
var db = require('./config/db');
// models
var User = require('./app/models/users');
var Message = require('./app/models/messages');
//parsing
app.use(bodyParser.json()); // for parsing application/json
app.use(bodyParser.urlencoded({ extended: true })); //for parsing url encoded
//AUTH========================================================
app.use(cookieParser());
app.use(require('express-session')({
secret: 'white rabbit',
resave: false,
saveUninitialized: false
}));
app.use(passport.initialize());
app.use(passport.session());
// passport config
var Member = require('./app/models/members');
passport.use(new LocalStrategy(Member.authenticate()));
passport.serializeUser(Member.serializeUser());
passport.deserializeUser(Member.deserializeUser());
// view engine ejs
app.set('view engine', 'ejs');
//chat namespace
var chatSocket = io.of('/chat')
//routes
require('./app/routes/routes')(app, chatSocket);
//Heroku port
app.set('port', (process.env.PORT || 5000));
//ADMIN====================================================
//create an admin account if none exists
var admin = Member.find({admin: true}, function(err, admins) {
if (err) throw err
else if(admins.length == 0){
//no admin. create default account
Member.register(new Member({username: "admin", admin: true}), "mypassword", function(err, admin){
if(err) throw err;
console.log('Defaut account created successfully!');
})
}
else{
//at least one admin exists
console.log('Admin account already exists : ');
console.log(admins)
}
});
//START ===================================================
http.listen(app.get('port'), function(){
console.log('listening on port ' + app.get('port'));
});
//SOCKET ==================================================
require('./app/controllers/socket')(chatSocket, User, Message);
You didn't set any route that points to /
Point to that route by using app.get
app.get("/", function(req, res) {
res.send("home");
});
There are available routes in /app/routes/*.js files of the repository you cloned.

I cannot send chat messages with socket.io

I could send messages before, but I shared passport's sessions with express and socket.io using redis by following this tutorial http://www.scotthasbrouck.com/blog/2016/3/18/passportjs-express-session-with-sockeio and now I can no longer send any chat messages.
Also, in my routes req.isAuthenticated() always returns false but I didn't have this problem before.
This is my server.js.
// server.js
// set up ======================================================================
// get all the tools we need
var express = require('express');
var app = express();
var server = require('http').Server(app);
var port = process.env.PORT || 8080;
var mongoose = require('mongoose');
var passport = require('passport');
var flash = require('connect-flash');
var morgan = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var configDB = require('./config/database.js');
var http = require('http').Server(app);
var io = require('socket.io')(http);
var passportSocketIo = require('passport.socketio');
var session = require('express-session');
var chatdb = require('./app/models/chat.js');
var user = require('./app/models/user.js');
var redis = require('redis');
var client = redis.createClient();
var RedisStore = require('connect-redis')(session);
// configuration ===============================================================
mongoose.connect(configDB.url); // connect to our database
require('./config/passport')(passport); // pass passport for configuration
// set up our express application
app.use(morgan('dev')); // log every request to the console
app.use(cookieParser()); // read cookies (needed for auth)
app.use(bodyParser()); // get information from html forms
app.set('view engine', 'ejs'); // set up ejs for templating
var sessionStore = new RedisStore({ host: 'localhost', port: 6379, client: client, ttl: 260 });
// required for passport
app.use(session({
secret: 'secret',
store: sessionStore,
resave: true,
saveUninitialized: true,
cookie: {
secure: process.env.ENVIRONMENT !== 'development' && process.env.ENVIRONMENT !== 'test',
maxAge: 2419200000
},
}));
app.use(passport.initialize());
app.use(passport.session()); // persistent login sessions
app.use(flash()); // use connect-flash for flash messages stored in session
app.use(express.static(__dirname + '/views'));
app.use(express.static(__dirname + '/public'));
io.use(passportSocketIo.authorize({
key: 'connect.sid',
secret: 'secret',
store: sessionStore,
passport: passport,
cookieParser: cookieParser,
}));
var eventSocket = io.of('/chat');
// socket.io
io.on('connection', function (socket) {
console.log('a user connected');
socket.on('chat message', function(msg){
var name = "efe";
chatdb.saveMsg({name: name, msg: msg}, function(err){
if(err) throw err;
io.emit('chat message', msg);
});
if (socket.request.user && socket.request.user.logged_in) {
console.log(socket.request.user);
}
});
});
// routes ======================================================================
require('./app/routes.js')(app, passport); // load our routes and pass in our app and fully configured passport
// launch ======================================================================
http.listen(port);
console.log('The magic happens on port ' + port);
I had the same problem. I tried to implement passport.socketio like you but I solved my problem without it.
Here is my middleware :
// Express session middleware
var sessionMiddleware = session({ secret: 'secret-key', resave: true, saveUninitialized: true });
// Send Express sessionMiddleware through socket.io
io.use(function(socket, next){
// Params: request object, response object and callback.
sessionMiddleware(socket.request, {}, next);
});
The second parameter (response object) of sessionMiddleware function is empty. This will renders the session read-only.
And Here is how I use passport js session variable to get user informations :
io.on("connection", function(socket){
socket.on('chat message', function(msg){
var passport = socket.request.session.passport; // Get the passport variable
// Check if passport session exists
if (passport && typeof passport !== 'undefined'){
var userSession = passport.user; // Get the user session
// Build JSON with user session data
var message = {
message : msg,
name : userSession.name,
avatar : userSession.avatar
};
io.emit('chat message', message); // Emit my socket
}
});
});
Hope it help.
This was how i was able to solve it.
var express = require('express');
var app = express();
var server = require('http').Server(app);
var port = process.env.PORT || 8080;
var mongoose = require('mongoose');
var passport = require('passport');
var flash = require('connect-flash');
var morgan = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var session = require('express-session');
// Add connect-mongo to project - npm install connect-mongo
var MongoStore = require('connect-mongo')(session);
var configDB = require('./config/database.js');
var http = require('http').Server(app);
var io = require('socket.io')(http);
var chatdb = require('./app/models/chat.js');
// configuration ===============================================================
// NOTE: This might need to be put into a callback/promise inside an initialize function
var db = mongoose.connect(configDB.url); // connect to our database
require('./config/passport')(passport); // pass passport for configuration
// set up our express application
app.use(morgan('dev')); // log every request to the console
app.use(cookieParser()); // read cookies (needed for auth)
app.use(bodyParser()); // get information from html forms
app.set('view engine', 'ejs'); // set up ejs for templating
var mongoStore = new MongoStore({
mongooseConnection: db.connection,
});
app.use(session({
secret: 'secret',
clear_interval: 900,
cookie: { maxAge: 2 * 60 * 60 * 1000 },
store: mongoStore,
}));
// required for passport
app.use(session({ secret: 'secret' })); // session secret
app.use(passport.initialize());
app.use(passport.session()); // persistent login sessions
app.use(flash()); // use connect-flash for flash messages stored in session
app.use(express.static(__dirname + '/views'));
app.use(express.static(__dirname + '/public'));
// Intercept Socket.io's handshake request
io.use(function(socket, next) {
// Use the 'cookie-parser' module to parse the request cookies
cookieParser('secret')(socket.request, {}, function(err) {
// Get the session id from the request cookies
var sessionId = socket.request.signedCookies ? socket.request.signedCookies['connect.sid'] : undefined;
if (!sessionId) return next(new Error('sessionId was not found in socket.request'), false);
// Use the mongoStorage instance to get the Express session information
mongoStore.get(sessionId, function(err, session) {
if (err) return next(err, false);
if (!session) return next(new Error('session was not found for ' + sessionId), false);
// Set the Socket.io session information
socket.request.session = session;
// Use Passport to populate the user details
passport.initialize()(socket.request, {}, function() {
passport.session()(socket.request, {}, function() {
// This will prohibit non-authenticated users from connecting to your
// SocketIO server.
if (socket.request.user) {
next(null, true);
} else {
next(new Error('User is not authenticated'), false);
}
});
});
});
});
});
// socket.io
io.on('connection', function(socket) {
socket.on('chat message', function(msg) {
console.log(socket.request.user.facebook.name || socket.request.user.local.email);
var name = socket.request.user.facebook.name || socket.request.user.local.email;
chatdb.saveMsg({
name: name,
msg: msg
}, function(err) {
if (err) throw err;
io.emit('chat message', msg);
});
});
socket.on('disconnect', function() {
console.log('user disconnected');
});
});
// routes ======================================================================
require('./app/routes.js')(app, passport); // load our routes and pass in our app and fully configured passport
// launch ======================================================================
http.listen(port);
console.log('The magic happens on port ' + port);

socket.io session does not update when req.session changes

I am currently working on a basic app where a user needs to authenticate (with passportJS) and then send a message to my server with socket.io. Here is the nodeJS code:
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var expressSession = require('express-session');
var mongoose = require('mongoose');
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var routes = require('./routes/index');
var api = require('./api/index');
var auth = require('./routes/auth');
var session = expressSession({secret: 'mySecret', resave: true, saveUninitialized: true});
var port = normalizePort(process.env.PORT || '3000');
var app = express();
var server = require('http').createServer(app);
var io = require('socket.io')(server);
var sharedsession = require('express-socket.io-session');
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.set('port', port);
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(session);
app.use(passport.initialize());
app.use(passport.session());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/bower_components', express.static(path.join(__dirname, 'bower_components')));
app.use('/', routes);
app.use('/api', api);
app.use('/auth', auth);
// passport config
var User = require('./models/user');
passport.use(new LocalStrategy({
usernameField: 'email'
}, User.authenticate()));
passport.use(require('./strategies/facebook'));
passport.use(require('./strategies/google'));
passport.serializeUser(function(user, done) {
done(null, { id: user._id });
});
passport.deserializeUser(function(obj, done) {
done(null, obj);
});
io.use(sharedsession(session, {
autoSave:true
}));
io.on('connection', function(socket) {
console.log('user connected');
console.log(socket.handshake.session);
socket.on('message-new', function(data) {
console.log('receiving message to create');
console.log(socket.handshake.session);
});
socket.on('disconnect', function() {
console.log('user disconnected');
});
});
server.listen(port);
So as you can see I use express-socket.io-session to be able to access the session in my socket and it is supposed to be the same than req.session. So at first when a user is connected to the socket.io (but not authenticated), his socket.handshake.session is equal to req.session so:
Session {
cookie:
{ path: '/',
_expires: null,
originalMaxAge: null,
httpOnly: true } }
once he authenticates, req.session becomes:
cookie:
{ path: '/',
_expires: null,
originalMaxAge: null,
httpOnly: true },
passport: { user: { id: 56a13e58150f42fc29b44b7a } } }
but when I emit a message-new from the client and that it displays socket.handshake.session, it is still equals to
Session {
cookie:
{ path: '/',
_expires: null,
originalMaxAge: null,
httpOnly: true } }
So the socket's session was not updated when req.session was. How can I change this behavior? I need to be able to know in my socket if the user is connected or not...
Inside your event listener 'new message' you can tell the session to reload, the docs don't explicitly say this, but it shares some of the same methods with the express-session
Inside your event listener you can tell session to reload
socket.handshake.session.reload(function(err) {
// this will give you the update session info
}
With the 'express-session' you can use the same method as in the docs

Using RedisStore in nodejs / expressjs

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()}));

Resources