This is my Express middleware stack:
var server = express()
.use(express.cookieParser())
.use(express.session({secret: 'Secret'}))
.use(express.bodyParser())
.use(function printSession(req, res, next) {
console.log(req.session.user);
next();
})
.use(express.static('./../'));
and here are two routes:
server.post('/setSession', function (req, res) {
req.session.user = 'admin';
}
server.post('/getSession', function (req, res) {
console.log(req.session.user);
}
Now the session management in the route handlers work find. I can set session.user and it will persist for the subsequent requests in the same session, as confirmed by getSession. However, the middleware function printSession always prints undefined.
How can I access the populated session object in the middleware?
This program works fine. Before I access /setSession, the middleware prints after session: undefined. Once I GET /setSession, it prints after session: admin. As long as the browser you are testing with (not curl) stores and sends the session cookies, this will work as expected.
var express = require('express');
var server = express();
server.use(express.cookieParser());
server.use(express.session({secret: 'SEKRET'}));
server.use(function (q,r,n) {console.log('after session:', q.session.user);n();});
server.get('/', function (q,r,n) {r.send("you got slashed");});
server.get('/setSession', function (req, res) {
console.log("logging admin in via /setSession");
req.session.user = 'admin';
res.send("admin logged in");
});
server.listen(3000);
There must be something wrong with your settings. The following example, that is very similar to your code but uses GET instead POST, works fine for me
app.configure(function(){
// ...
app.use(express.cookieParser('your secret here'));
app.use(express.session());
app.use(function(req, res, next) {
console.log(req.session.user + ' from middleware');
next();
});
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));
});
and
app.get('/getSession', function(req, res) {
console.log(req.session.user);
res.send('awesome');
});
app.get('/setSession', function(req, res) {
req.session.user = 'admin';
res.send('done');
});
Now when you do the following everything works as expected
GET /getSession => undefined from middleware, undefined
GET /setSession => undefined from middleware
GET /getSession => admin from middleware, admin
Related
I have an Express.js app with a Passport-local Auth, I'm tying to implement express router to my app since it's getting really hard to debug
This is an example of my main file (app.js)
const express = require('express')
const app = express()
const passport = require('passport')
const testing = require('./routes/file')
app.use(passport.initialize())
app.use(passport.session())
app.use('/router', testing)
const initializePassport = require('./passport-config');
initializePassport.initialize(passport);
app.get('/', checkAuthenticated, (req, res) => {
let user = data.key
res.send(`Hi ${user}`)
})
app.post('/login', checkNotAuthenticated, passport.authenticate('local', {
successRedirect: '/',
failureRedirect: '/login',
failureFlash: true
}))
function checkAuthenticated(req, res, next) {
if (req.isAuthenticated()) {
return next()
}
res.redirect('/login')
}
function checkNotAuthenticated(req, res, next) {
if (req.isAuthenticated()) {
return res.redirect('/')
}
next()
}
app.listen(3000)
This is what my main file is like, this works perfectly fine
and just to make things clear, The function are to check if a user is authenticated or not, also my passport-config returns something called data.key which is basically the username of the user.
Now I've created a router here app.use('/router', testing) with the route as /router for testing purposes
Now this is my file.js that is being used by express
const express = require('express'), router = express.Router();
var bodyParser = require('body-parser');
// Handle POST requests
router.use(bodyParser.urlencoded({ extended: false }));
router.use(bodyParser.json());
router.get('/test', checkAuthenticated, (req, res) => {
let user = data.key;
res.send(`Hello ${user}, this is coming from the router`)
})
module.exports = router;
Now as expected when I open the site at localhost:3000/router/test it returns a undefined error for data.key since it's not imported and then when I comment that out the line causing the error then checkAuthenticated doesn't work, even when I'm not logged in I can get access to the page, now this is the problem, how do I fix it, I've gone through the entire express router docs I couldn't find luck there.
Thanks
Your function is not in the global scope you need to set it to global to be able to see it like:
GLOBAL.authFunction = function(){
}
Suggestion:
1- make a module for auth name it authModule.
2- import the module auth check middleware where ever you want.
I know there are lots of questions similar to this, I checked the questions asked before and none of the answers did solve my problem. I m developing a simple authentication node.js app for now (the front end is react-native, the database is MongoDB). I m using following packages for this:
passport-local-mongoose
express-session
passport-local
passport
So here is the app.js
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var cors = require('cors');
var passport = require('passport');
var user = require('./models/user');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var cookieParser = require('cookie-parser')
var app = express();
app.use(cookieParser('keyboard cat'));
var corsOptions = {
origin: '*',
credentials: true };
app.use(cors(corsOptions))
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(express.static(path.join(__dirname, 'public')));
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
//auth settings
app.use(require("express-session")({
secret: 'keyboard cat',
resave: false,
saveUninitialized: false,
}));
app.use(passport.initialize());
app.use(passport.session());
passport.use(user.createStrategy());
passport.serializeUser(user.serializeUser());
passport.deserializeUser(user.deserializeUser());
app.use('/', indexRouter);
app.use('/users', usersRouter);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
Here is the user model:
var mongoose=require('mongoose');
var passportLocalMongoose = require('passport-local-mongoose');
var userShema = new mongoose.Schema({
username : String,
password : String
})
userShema.plugin(passportLocalMongoose);
var user= mongoose.model("User",userShema);
module.exports = user;
Here is my route file
var express = require('express');
var router = express.Router();
var user= require("../models/user");
const passport = require('passport');
var isLoggedIn =require('../session');
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
router.post('/login', function(req, res, next) {
passport.authenticate('local' ,function(err, user, info) {
if (err) { return next(err); }
if (!user) { return res.send("-1"); }
req.logIn(user, function(err) {
if (err) { return next(err); }
req.session.save(() => res.send("Başarılı"));
});
})(req, res, next);
});
router.post('/signUp', async function(req, res, next) {
try{
console.log('registering user');
user.register(new user({username: req.body.username}), req.body.password, function(err) {
if (err) {
console.log('error while user register!', err);
return next(err);
}
console.log('user registered!');
res.redirect('/');
});
}
catch(e){
console.log(e);
res.status(503).send("-1")
}
});
router.get('/logOut', function(req,res,next){
req.logOut();
res.send("1");
})
router.get('/home',isLoggedIn,function(req,res,next){
res.send("Success");
})
module.exports = router;
And finally here is the session.js
const passport = require('passport');
var isLoggedIn =(req,res,next) =>{
if(req.isAuthenticated()){
return next();
}
res.status(403).send("Something went wrong")
}
module.exports = isLoggedIn;
The problem is here, after authentication (which works fine), React native goes to the home page and I wanna take some information as the user logged in.For this i m using isLoggedIn function which uses req.isAuthenticated() and returns always false.
The most common answers that I've tried and didn't work are
Make sure session-passport.init-passport.session lines in the correct order (which already is in my app)
Issue related clients get-post call (in my react-native app -> axios.post(BaseURL+url,data,{ withCredentials: true }) , also in server app -> var corsOptions = {
origin: '*',
credentials: true };
app.use(cors(corsOptions)))
Some say if you are working with https you have to set {secure:true} ( which I m not)
One said "After authenticating, passport.js requires you to reroute/redirect"otherwise the session is not created, but lots of people also having problems with redirect. I did try it didn't solve the issue.
One said don't use express-session, use client-sessions (i did try that, didn't work)
Some people suggest to change serialize and deserialize functions ( i tried other codes that I found on the internet, none of them worked) but the problem is my deserialize function never runs(i think this function works after isAuthenticated() and checks the user info on the req but my req does not have that info. Basically, I can log in to the app but it doesn't save my session in request.)
A person suggests that " express-session tries to delay the redirect, but some browsers don't wait for the whole response before directing. So you need to manually save before redirecting." and it solved almost everyone's problem but me. (In my code as you can see req.session.save(() => res.send("Başarılı")); )
Also, another person said putting delay also works the issue ( i tried, it didn't)
So if anybody has another solution besides these, please share. I am open to all suggestions.
I kinda solved the problem by changing the server code a bit. I had to take a break since last time I was working related to this project so there are some parts I don't exactly remember why I had to change but, at the end of the day, code works.
I think something was wrong between express-session and passport so that session created but no passport object in req.session.
In App.js, i have to add some new libraries:
const { v4: uuidv4 } = require('uuid');
const FileStore = require('session-file-store')(session);
const LocalStrategy = require('passport-local').Strategy;
const bodyParser = require("body-parser");
I used some default code provided by express-session and passport before and they didn't work. So I started to change the session first a bit. To do that I need to import a library to create random session-id (uuid), also I started to save sessions in a file from the server-side. I guess I didn't have to import any library to save data, I could hold all info in the database but I prefer to move along with using session-file-store library. I also added the passport-local library to this file (it was used on the user model only before). Lastly, I had to add body-parser library to parse the response. I have to indicate that I was using express.urlencoded() function before and it was working fine for my routing. I didn't have to use another library to parse the request body. As far as I remember when I add some middleware for the session, this express.urlencoded didn't work, and I was like let's try other one and put body-parser library in my code and it just work fine.
app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.urlencoded({ extended: false }))
I don't know the exact difference between these 2 lines. But I know that they work differently and it seems body-parser library works better than express parser.
I changed the settings of my session
app.use(session({
genid: (req) => {
console.log('Inside the session middleware')
console.log(req.sessionID)
return uuidv4(); // use UUIDs for session IDs
},
store: new FileStore(),
secret: 'keyboard cat',
resave: false,
saveUninitialized: true
}))
So basically I create id with session object and I saved it to request. This code works before my router so every request has a sessionId. I think express-session checks if a request has sessionId and is it saved to the server-side before calling genId function which means that this function is called only if the request has no session-id or the session id is not stored in the server.
Browsers save your session Id and use the same id for each request. The sessions saved in the server as objects hold the cookie info for the session. Passport.js
puts your userId or username into the cookie (if you are logged in of course) so we can separate if that cookie is related to an account or not.
I was using the default strategy method coming from passport-local, but I re-write it. LocalStrategy function is the place that performs authentication when a request sent to '..../login'.In login (post) function, you use passport.authenticate('local' ,function(err, user, info) {} -> Here local indicates that use the local strategy that u decided in app.js
passport.use(new LocalStrategy(
function(username, password, done) {
console.log("passport localStrategy",username,password)
user.findOne({ username: username }, function (err, user) {
user.authenticate(password).then(res => {
if (err) { return done(err); }
if (!user) { return done(null, false); }
if (!res.user) { return done(null, false); }
console.log('Local strategy works fine')
return done(null, user);
})
});
}
));
//takes user and save it to session file store
//saves the user id in the request object as request.session.passport
//and adds request object as request.user.
passport.serializeUser(function(user, done) {
console.log('Inside serializeUser callback. User id is save to the session file store here')
done(null, user);
});
passport.deserializeUser(function(user, done) {
console.log('Inside De-serializeUser callback.')
done(null,user)
});
I don't recommend you to serialize the only user.id if you re using MongoDB (at least don't do this until you re sure that other parts of your program work without error). I had some problems with deserializeUser with findById (my problems were related to using default objectIds that MongoDB created automatically) function. It wasn't giving any error but returned to 500 as a response.
SerializeUser is called after login and put your info into the cookie. DeserializeUser is called if your request has the cookie that is saved on your server-side.
In Index.js (my router file)
router.post('/login', function(req, res, next) {
console.log("inside of the login",req.sessionID)
//passport.authenticate with local parameter will call function that configured in passport.use(new strategyCalss)
passport.authenticate('local' ,function(err, user, info) {
console.log('Inside passport.authenticate() callback');
console.log(`req.session.passport: ${JSON.stringify(req.session.passport)}`)
console.log(`req.user: ${JSON.stringify(req.user)}`)
if (err) { return next(err); }
if (!user) { return res.send("-1"); }
//req.login calls passport.serialize user
req.login(user, function(err) {
console.log('Inside req.login() callback')
console.log(`req.session.passport: ${JSON.stringify(req.session.passport)}`)
console.log(`req.user: ${JSON.stringify(req.user)}`)
if (err) { return next(err); }
return res.send('You were authenticated & logged in!\n');
});
})(req, res, next);
});
I changed my login function like this. So it actually worked fine when you changed session settings a bit. I even deleted the session.save() part because the session was even created before.My problem was that session data didn't save as object in the session so I tried to force to save it.
After all these changes, server-side works fine. I tested this code with the postman and it worked perfectly. However even though I send a cookie to the browser, the browser didn't save my cookie. There is something wrong related to the front-end or browser. However, this issue at the server side is resolved.
I'm trying to add local authentication to my node.js app. After following the tutorial on: https://scotch.io/tutorials/easy-node-authentication-setup-and-local I have run into error: "TypeError: app.use() requires a middleware function".
I think this is related to the app.use(indexRoutes) in my app.js file but I'm not sure how to fix this? Any help would be greatly appreciated.
Here is my code so far:
app.js:
var express = require('express'),
session = require("express-session"),
bodyParser = require('body-parser'),
app = express().use(bodyParser.json()), //creates express http server
passport = require('passport'),
sanitizer = require('express-sanitizer'),
mongoose = require("mongoose"),
cookieParser = require('cookieparser'),
dotnev = require('dotenv').config(),
https = require('https'),
flash = require('connect-flash'),
fs = require('fs'),
config = require('./config/config'),
_ = require("underscore");
require('./config/passport')(passport);
var indexRoutes = require("./routes/index")(app, passport);
app.use(bodyParser.urlencoded({extended: true}));
app.use(sanitizer());
app.use(express.static(__dirname + "/public")); //tells express to serve the contents of the public directory
app.use(cookieParser);
//no longer need to specify that the view files are .ejs
app.set("view engine", "ejs");
app.use(session({
secret: "akjjkjnisaiuu8998323jdkadsih892rhoisdfasl",
resave: true,
saveUninitialized: true,
cookie: {
maxAge: 1200000
}
}));
app.use(passport.initialize);
app.use(passport.session());
app.use(flash());
app.use(indexRoutes);
mongoose.connect(process.env.MONGOLAB_URL, { useNewUrlParser: true });
index.js:
var express = require("express"),
router = express.Router(),
_ = require("underscore"),
User = require("../models/user"),
auth = require("../routes/auth"),
config = require('../config/config'),
freshbooks = require("../modules/freshbooks"),
quickbooks = require("../modules/quickbooks");
module.exports = function(router, passport){
//------------------------------------//
//***------------ROUTES------------***//
//------------------------------------//
router.get("/", function(req, res) {
res.render("landing");
});
router.get("/register", auth.optional, function(req, res) {
res.render("register");
});
router.get("/login", auth.optional, function(req, res) {
res.render("login");
});
router.get("/admin", isLoggedIn, function(req, res) {
res.render('admin', {
user : req.user // get the user out of session and pass to template
});
});
//------------------------------------//
//***-------------AUTH-------------***//
//------------------------------------//
router.post('/register', passport.authenticate('local-signup', {
successRedirect : '/admin', // redirect to the secure profile section
failureRedirect : '/register', // redirect back to the signup page if there is an error
failureFlash : true // allow flash messages
}));
router.post('/login', passport.authenticate('local-login', {
successRedirect : '/profile', // redirect to the secure profile section
failureRedirect : '/login', // redirect back to the signup page if there is an error
failureFlash : true // allow flash messages
}));
function isLoggedIn(req, res, next) {
// if user is authenticated in the session, carry on
if (req.isAuthenticated())
return next();
// if they aren't redirect them to the home page
res.redirect('/');
}
router.get('/logout', function(req, res) {
req.logout();
res.redirect('/');
});
}
Thanks in advance for any help!
In app.js
var { registerIndexRoutes } = require("./routes/index");
var indexRoutes = registerIndexRoutes(router, passport);
app.use(indexRoutes);
and index.js
const registerIndexRoutes = function(router, passport){
//------------------------------------//
//***------------ROUTES------------***//
//------------------------------------//
router.get("/", function(req, res) {
res.render("landing");
});
return router;//important;
}
module.exports = { registerIndexRoutes };
It will help you.
You're getting that error because, this function, module.exports = function(router, passport){, is not a valid middleware.
From express docs: Middleware functions are functions that have access to the request object (req), the response object (res), and the next function in the application’s request-response cycle.
The syntax goes:
function(req, res, next) {
// Implement the middleware function based on the options object
next()
}
req: HTTP response argument to the middleware function, called "res" by convention.
res: HTTP request argument to the middleware function, called "req" by convention.
next: Callback argument to the middleware function, called "next" by convention.
When you invoked this function, function(router, passport){:
var indexRoutes = require("./routes/index")(app, passport);
indexRoutes, contains the return value of function(router, passport) which does not return a middleware function (It returns undefined).
Two ways you can solve the issue:
Change your import:
// remove this line and put the below instead
app.use(cookieParser);
// and modify and move your import
require("./routes/index")(app, passport);
Use Express router: Change your index.js like
// note your exports it's not a function, you're exporting this **router** object -> router = express.Router(),
module.exports = router;
//------------------------------------//
//***------------ROUTES------------***//
//------------------------------------//
router.get("/", function(req, res) {
res.render("landing");
});
router.get("/register", auth.optional, function(req, res) {
res.render("register");
});
...
And change your import to:
var indexRoutes = require("./routes/index");
I am using current express 4 and node.js 6.x. In my web application I need to do an internal redirect (i.e. redirect from one route handler to another, without sending a redirect to the client). This works within toplevel express or within the same router, but not if the source request is located in a Router.
Please see the following minimal working example:
const express = require("express");
const app = module.exports.app = express();
const router = new express.Router();
app.use("/myrouter", router);
// not working
router.get("/test", (req, res, next) => {
req.url = "/toplevel";
next();
});
// working
app.get("/test", (req, res, next) => {
req.url = "/toplevel";
next();
});
// debug output
app.use((req, res, next) => {
console.log(`request to ${req.url}`);
next();
});
app.get("/toplevel", (req, res) => {
res.end("toplevel");
});
app.listen(8000);
If I open "http://localhost:8000/test", I get the correct output "toplevel", and the debug output prints "request to /toplevel". Unfortunately it doesn't work for "http://localhost:8000/myrouter/test". The debug output prints "request to /myrouter/toplevel" and I get the result of the default express 404 handler.
Is there any may to redirect the request from "/myrouter/test" to "/toplevel" without redirecting the client (i.e. res.redirect())?
I have the following function that I placed inside a separate js file.
I am trying to use it inside another javascript file that requires passport.js, and I would like to call it using app.use to further modularize my application
var express = require('express');
var router = express.Router();
/* GET welcome page. */
router.get('/home', isLoggedIn, function(req, res, next) {
res.render('home', {
title: 'title',
user : req.user
});
});
// route middleware to make sure
function isLoggedIn(req, res, next) {
// if user is authenticated in the session
if (req.isAuthenticated())
return next();
// if they aren't redirect them to the home page
res.redirect('/');
}
module.exports = router;
The reason I created it is so I reduce redundancy and not use the following code each time:
app.get('/home', isLoggedIn, function(req, res) {
res.render('home.ejs', {
user : req.user // get the user out of session and pass to template
});
});
However I can't seem to get it to work. is authenticated is undefined although it is in the same folder, and it gives me an error 404 not found when I issue a get. How I can keep it in an external file and still use it? should I also pass it the user argument from where I am calling it?
var express = require('express');
var router = express.Router();
module.exports = function (app, passport){
router.get('/home', isLoggedIn, function(req, res, next) {
res.render('home', {
title: 'title',
user : req.user
});
});
return router;
};
function isLoggedIn(req, res, next) {
// if user is logged in -
if (req.isAuthenticated())
return next();
// if they aren't redirect them to home
res.redirect('/');
}