Passport + NodeJs + Express 得到“req.user”未定义
Posted
技术标签:
【中文标题】Passport + NodeJs + Express 得到“req.user”未定义【英文标题】:Passport + NodeJs + Express getting "req.user" undefined 【发布时间】:2019-08-13 18:28:02 【问题描述】:我面临一个会话问题,在成功通行证后获取 req.user 未定义。验证方法。
基本上在注册或登录后,当我重定向时,无法在请求变量中找到“用户”。
我使用了一个使用 mongo 的 hackathon 启动器,我试图改变一些东西以使用 Postgres。
编辑 -- 遵循评论建议后
现在注册流程工作正常,但登录流程有一些问题。发生了一些奇怪的事情,当我添加很多断点时,它似乎间歇性地登录。使用评论建议更新代码
app.js
const express = require('express');
const compression = require('compression');
const session = require('express-session');
const bodyParser = require('body-parser');
const logger = require('morgan');
const chalk = require('chalk');
const errorHandler = require('errorhandler');
const lusca = require('lusca');
const dotenv = require('dotenv');
const flash = require('express-flash');
const path = require('path');
const passport = require('passport');
const expressValidator = require('express-validator');
const expressStatusMonitor = require('express-status-monitor');
const sass = require('node-sass-middleware');
const multer = require('multer');
dotenv.load( path: '.env.example' );
const SequelizeStore = require('connect-session-sequelize')(session.Store);
const models = require('./models');
const upload = multer( dest: path.join(__dirname, 'uploads') );
/**
* Load environment variables from .env file, where API keys and passwords are configured.
*/
/**
* Controllers (route handlers).
*/
const homeController = require('./controllers/home');
const userController = require('./controllers/user');
const contactController = require('./controllers/contact');
const dashController = require('./controllers/dash');
const currencyController = require('./controllers/currency');
const accountController = require('./controllers/account');
const testController = require('./controllers/test');
const txController = require('./controllers/transaction');
/**
* API keys and Passport configuration.
*/
const passportConfig = require('./config/passport');
/**
* Create Express server.
*/
const app = express();
/**
* Express configuration.
*/
app.set('host', '127.0.0.1');
app.set('port', 8080);
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
app.use(expressStatusMonitor());
app.use(compression());
app.use(sass(
src: path.join(__dirname, 'public'),
dest: path.join(__dirname, 'public')
));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded( extended: true ));
app.use(expressValidator());
app.use(session(
resave: true,
saveUninitialized: true,
secret: process.env.SESSION_SECRET,
cookie: maxAge: 1209600000 , // two weeks in milliseconds
store: new SequelizeStore(
db: models.sequelize
)
));
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
app.use((req, res, next) =>
// if (req.path === '/api/upload')
// next();
// else
// lusca.csrf()(req, res, next);
//
next();
);
app.use(lusca.xframe('SAMEORIGIN'));
app.use(lusca.xssProtection(true));
app.disable('x-powered-by');
app.use((req, res, next) =>
res.locals.user = req.user;
next();
);
app.use((req, res, next) =>
// After successful login, redirect back to the intended page
if (!req.user
&& req.path !== '/login'
&& req.path !== '/signup'
&& !req.path.match(/^\/auth/)
&& !req.path.match(/\./))
req.session.returnTo = req.originalUrl;
else if (req.user
&& (req.path === '/account' || req.path.match(/^\/api/)))
req.session.returnTo = req.originalUrl;
next();
);
app.use('/', express.static(path.join(__dirname, 'public'), maxAge: 31557600000 ));
app.use('/js/lib', express.static(path.join(__dirname, 'node_modules/chart.js/dist'), maxAge: 31557600000 ));
app.use('/js/lib', express.static(path.join(__dirname, 'node_modules/popper.js/dist/umd'), maxAge: 31557600000 ));
app.use('/js/lib', express.static(path.join(__dirname, 'node_modules/bootstrap/dist/js'), maxAge: 31557600000 ));
app.use('/js/lib', express.static(path.join(__dirname, 'node_modules/jquery/dist'), maxAge: 31557600000 ));
app.use('/webfonts', express.static(path.join(__dirname, 'node_modules/@fortawesome/fontawesome-free/webfonts'), maxAge: 31557600000 ));
/**
* Primary app routes.
*/
app.get('/', homeController.index);
app.get('/login', userController.getLogin);
app.post('/login', userController.postLogin);
app.get('/logout', userController.logout);
app.get('/forgot', userController.getForgot);
app.post('/forgot', userController.postForgot);
app.get('/reset/:token', userController.getReset);
app.post('/reset/:token', userController.postReset);
app.get('/signup', userController.getSignup);
app.post('/signup', userController.postSignup);
// app.get('/account', passportConfig.isAuthenticated, userController.getAccount);
// app.post('/account/profile', passportConfig.isAuthenticated, userController.postUpdateProfile);
app.post('/account/password', passportConfig.isAuthenticated, userController.postUpdatePassword);
// app.post('/account/delete', passportConfig.isAuthenticated, userController.postDeleteAccount);
// app.get('/account/unlink/:provider', passportConfig.isAuthenticated, userController.getOauthUnlink);
app.get('/dashboard', passportConfig.isAuthenticated, dashController.index);
app.get('/test', passportConfig.isAuthenticated, testController.test);
// app.get('/contact', contactController.contact);
// app.post('/addContact', contactController.addContact);
// app.post('/editContact', contactController.editContact);
// app.get('/listContacts', contactController.listContacts);
// app.get('/listCurrency', currencyController.listCurrency);
// app.post('/addAccount', accountController.addAccount);
// app.post('/editAccount', accountController.editAccount);
// app.get('/listAccounts', accountController.listAccounts);
// app.get('/getTransactions', txController.getTransactions);
/**
* Error Handler.
*/
if (process.env.NODE_ENV === 'development')
// only use in development
app.use(errorHandler());
else
app.use((err, req, res, next) =>
console.error(err);
res.status(500).send('Server Error');
);
/**
* Start Express server.
*/
models.sequelize.sync().then(() =>
app.listen(app.get('port'), () =>
console.log('%s App is running at http://localhost:%d in %s mode', chalk.green('✓'), app.get('port'), app.get('env'));
console.log('Press CTRL-C to stop\n');
);
);
module.exports = app;
user.js
const promisify = require('util');
const crypto = require('crypto');
const nodemailer = require('nodemailer');
const passport = require('passport');
const models = require('../models');
const User = models;
const randomBytesAsync = promisify(crypto.randomBytes);
/**
* GET /login
* Login page.
*/
exports.getLogin = (req, res) =>
if (req.user)
return res.redirect('/');
res.render('account/login',
title: 'Login'
);
;
/**
* POST /login
* Sign in using email and password.
*/
exports.postLogin = (req, res, next) =>
req.assert('email', 'Email is not valid').isEmail();
req.assert('password', 'Password cannot be blank').notEmpty();
req.sanitize('email').normalizeEmail( gmail_remove_dots: false );
const errors = req.validationErrors();
if (errors)
req.flash('errors', errors);
return res.redirect('/login');
passport.authenticate('local', (err, user, info) =>
if (err) return next(err);
if (!user)
req.flash('errors', info);
return res.redirect('/login');
req.logIn(user, (err) =>
if (err) return next(err);
res.locals.user = user; //Updated code after comment suggestions
req.flash('success', msg: 'Success! You are logged in.' );
res.redirect('/dashboard');
);
)(req, res, next);
;
/**
* GET /logout
* Log out.
*/
exports.logout = (req, res) =>
req.logout();
req.session.destroy((err) =>
if (err) console.log('Error : Failed to destroy the session during logout.', err);
req.user = null;
res.redirect('/');
);
;
/**
* GET /signup
* Signup page.
*/
exports.getSignup = (req, res) =>
if (req.user)
return res.redirect('/');
res.render('account/signup',
title: 'Create Account'
);
;
/**
* POST /signup
* Create a new local account.
*/
exports.postSignup = (req, res, next) =>
req.assert('email', 'Email is not valid').isEmail();
req.assert('password', 'Password must be at least 4 characters long').len(4);
req.assert('confirmPassword', 'Passwords do not match').equals(req.body.password);
req.sanitize('email').normalizeEmail( gmail_remove_dots: false );
const errors = req.validationErrors();
if (errors)
req.flash('errors', errors);
return res.redirect('/signup');
User.findAll( limit: 1, where: email: req.body.email , plain: true )
.then((existingUser) =>
if (existingUser)
req.flash('errors', msg: 'Account with that email address already exists.' );
return res.redirect('/signup');
User.create(
email: req.body.email,
password: req.body.password
).then((user) =>
req.logIn(user, (err) =>
if (err) return next(err);
res.locals.user = user; //updated code after comment suggestions
return res.redirect('/');
);
).catch(error => next(error));
);
;
passport.js
const passport = require('passport');
const request = require('request');
const Strategy: LocalStrategy = require('passport-local');
const _ = require('lodash');
const models = require('../models');
passport.serializeUser((user, done) =>
done(null, user.id);
);
passport.deserializeUser((id, done) =>
models.User.findAll( where: id , limit: 1, plain: true )
.then(user => done(null, user))
.catch(err => done(err));
);
/**
* Sign in using Email and Password.
*/
passport.use(new LocalStrategy( usernameField: 'email' , (email, password, done) =>
models.User.findAll( where: email , limit: 1, plain: true ).then((user) =>
if (!user)
return done(null, false, msg: `Email $email not found.` );
user.comparePassword(password, (err, isMatch) =>
if (err) return done(err);
if (isMatch)
return done(null, user);
return done(null, false, msg: 'Invalid email or password.' );
);
).catch(error => done(error));
));
/**
* OAuth Strategy Overview
*
* - User is already logged in.
* - Check if there is an existing account with a provider id.
* - If there is, return an error message. (Account merging not supported)
* - Else link new OAuth account with currently logged-in user.
* - User is not logged in.
* - Check if it's a returning user.
* - If returning user, sign in and we are done.
* - Else check if there is an existing account with user's email.
* - If there is, return an error message.
* - Else create a new account.
*/
/**
* Login Required middleware.
*/
exports.isAuthenticated = (req, res, next) =>
if (req.isAuthenticated())
return next();
res.redirect('/login');
;
/**
* Authorization Required middleware.
*/
exports.isAuthorized = (req, res, next) =>
const provider = req.path.split('/').slice(-1)[0];
const token = req.user.tokens.find(token => token.kind === provider);
if (token)
next();
else
res.redirect(`/auth/$provider`);
;
【问题讨论】:
Node + Express + Passport: req.user Undefined的可能重复 伙计,它成功了.. 谢谢.. 你也能解释一下为什么需要这样做。我还添加了“ res.locals.user = user;”在重定向之前。这是添加它的正确方法。 很高兴它对你有用。这就是我在请求中传递我的用户对象的方式。更多解释在这里:app.locals 这很奇怪,不能正常工作,有时登录有时不登录。我认为这是某处的 asyc 调用问题..无法弄清楚在哪里 【参考方案1】:在你的app.js
中,你需要在初始化passport
之后调用const passportConfig = require('./config/passport');
,像这样:
app.use(passport.initialize());
app.use(passport.session());
// place it here
const passportConfig = require('./config/passport')(passport);
此外,您需要调整您的密码配置文件 (./config/passport
),以便在模块加载时它可以获取您在app.js
中实例化的passport
实例,并且随后使用它而不是通过require('passport')
加载新的passport
实例 - 我认为这会搞砸;虽然没有测试它。 :)
【讨论】:
【参考方案2】:您能否分享在您的 passport.js LocalStrategy 中引用此代码的用户对象示例
user.comparePassword(password, (err, isMatch) => ....);
看起来 user.id 在下面的 serializeuser 中不可用,这可能是它无法在会话中设置 user.id 并且无法反序列化用户进一步未在 req 中设置用户对象的原因
passport.serializeUser((user, done) =>
done(null, user.id);
);
【讨论】:
以上是关于Passport + NodeJs + Express 得到“req.user”未定义的主要内容,如果未能解决你的问题,请参考以下文章
NestJS / NodeJS / Passport / JWT - 股票当前用户
Nodejs + Passport.js + Redis:如何在 Redis 中存储会话
NodeJs:错误401(未经授权)我正在使用passport-jwt
nodejs - passport.use 回调返回 dataValues 和 _previousDataValues 而不是普通对象