Express-session + Passport + MongoDB - req.isAuthenticated() 登录后总是 return false

Express-session + Passport + MongoDB - req.isAuthenticated() always return false after login

我一直在寻找解决方案,因为即使在成功登录后 req.isAuthenticated() 总是 return false。

这些是我正在使用的软件包:

"express": "~4.16.1"
"express-session": "^1.17.1"
"mongoose": "^5.11.5"
"passport": "^0.4.1"
"passport-local": "^1.0.0"
"connect-mongo": "^3.2.0"

我正在使用 connect-mongo 在 MongoDB

中存储会话数据

我在这里提到过类似的问题

我已经尝试了所有可能的解决方案,仍然没有成功。

我的护照配置如下所示: 我不确定这是不是因为我的 serialization/deserialization

config/passport.js

const LocalStrategy = require('passport-local').Strategy;
const User = require('../schemas/UserSchema');

module.exports = function (passport) {
    // used to serialize the user for the session
    passport.serializeUser(function (user, done) {
        done(null, user._id); // I tried user.id still doesn't work since document ids in mongodb starts with "_id" ?
    });

    // used to deserialize the user
    passport.deserializeUser(function (id, done) {
        User.findById(id, function (err, user) {
            if (err) {
                return done(err);
            }

            done(err, user);
        });
    });


    passport.use(
        'local-login',
        new LocalStrategy({
            usernameField: 'email',
            passwordField: 'password',
            passReqToCallback: true
        }, async (req, email, password, done) => {
            try {
                const user = await User.findOne({ email });

                if (user) {
                    user.passwordMatch(password, function (err, match) {
                        if (err) {
                            return done();
                        }
                        if (match) {
                            return done(null, user);
                        } else {
                            return done(null, false, {
                                error: 'Incorrect credentials.'
                            });
                        }
                    });
                } else {
                    return done(null, false, { error: 'Incorrect credentials.' });
                }
            } catch (err) {
                return done(err);
            }
        })
    );
};

授权路线

authRoute.js

router.post(
    '/v1/authenticate',
    validateBody(schemas.loginSchema),
    (req, res, next) => {
        passport.authenticate('local-login', (err, user, info) => {
            if (err) {
                return next(err);
            }

            if (!user) {
                return res
                    .status(401)
                    .send(makeErrorJson({ type: INCORRECT_CREDENTIALS, status_code: 401, message: info.error }));
            } else {
                console.log('LOGIN SUCCESS, IS AUTH: ', req.isAuthenticated()) // WHY IS IT FALSE?
                const userData = sessionizeUser(user);
                return res.status(200).send(userData); // I'M ABLE TO GET DATA IN POSTMAN
            }
        })(req, res, next);
    });

router.get('/v1/check-session', (req, res) => {
    console.log('IS AUTH:', req.isAuthenticated()) // STILL FALSE
    if (req.isAuthenticated()) {
        const user = sessionizeUser(req.user);
        res.status(200).send(makeResponseJson(user));
    } else {
        res.sendStatus(404);
    }
});

app.js

const createError = require('http-errors');
const express = require('express');
require('./db/db');
const path = require('path');
const session = require('express-session');
const mongoose = require('mongoose');
const logger = require('morgan');
const cors = require('cors');
const helmet = require('helmet');
const hpp = require('hpp');
const csurf = require('csurf');
const passport = require('passport');
const MongoStore = require('connect-mongo')(session);

const app = express();
const authRouter = require('./routes/api/v1/auth');

app.disable('x-powered-by');
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(cors());
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(helmet());
app.use(hpp());

const sessionOptions = {
  key: process.env.SESSION_NAME,
  secret: process.env.SESSION_SECRET,
  resave: false,
  saveUninitialized: true,
  cookie: {
    expires: 14 * 24 * 60 * 60 * 1000,
    secure: false,
  }, //14 days expiration
  store: new MongoStore({
    mongooseConnection: mongoose.connection,
    collection: 'session'
  })
};


console.log('NODE_ENV =', process.env.NODE_ENV);
if (process.env.NODE_ENV === 'production') {
  app.set('trust proxy', 1); // trust first proxy
  sessionOptions.cookie.secure = true // serve secure cookies
  sessionOptions.cookie.httpOnly = true // serve secure cookies
}

app.use(session(sessionOptions));
app.use(passport.initialize());
app.use(passport.session());


app.use(express.static(path.join(__dirname, 'public')));

app.use('/api', authRouter);

app.use(csurf());

// 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('server-error', { title: 'Server Error' });
});

require('./config/passport')(passport);

module.exports = app;

POSTMAN 中测试登录后,用户成功登录并且用户会话数据存储在数据库中。但仍然 req.isAuthenticated() return 错误。

我在本地登录成功后通过在我的路由中调用 req.logIn 找到了答案。

问题似乎是 passport.deserializeUser 没有被调用。 我已经提到这个问题 Passport deserializeUser not being called

If you are using the authenticate callback when you authenticate with passport you need to log the user in manually. It will not be called for you.

这是我在 /authenticate 路线上所做的更改。

router.post(
    '/v1/authenticate',
    validateBody(schemas.loginSchema),
    (req, res, next) => {
        passport.authenticate('local-login', (err, user, info) => {
            if (err) {
                return next(err);
            }

            if (!user) {
                return res
                    .status(401)
                    .send(makeErrorJson({ type: INCORRECT_CREDENTIALS, status_code: 401, message: info.error }));
            } else {
                req.logIn(user, function (err) { // I added this <-- Log user in
                    if (err) {
                        return next(err);
                    }

                    console.log('LOGIN SUCCESS, IS AUTH: ', req.isAuthenticated())
                    const userData = sessionizeUser(user);
                    return res.status(200).send(userData);
                });
            }
        })(req, res, next);
    });