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);
});
我一直在寻找解决方案,因为即使在成功登录后 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);
});