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:
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
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.
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments