车把无法访问对象的属性
在身份验证(使用Passport
模块)之后,使用req.user
对象呈现模板,如下所示,
app.get('/', (req, res) => {
console.log(`Router get user: ${req.user}`);
console.log("Router get user of type: " + (typeof req.user));
res.render('index', {
layout: false,
user: req.user,
});
});
我检查了req.user
by <代码> console.log ,用户
对象按预期打印,
Router get user: {
_id: new ObjectId("629e3821bfb2869c42ac3c4b"),
username: 'me',
password: '123'
}
第二个console.log
显示了req.user的类型是
对象
,
Router get user of type: object
String 之后,
app.get('/', (req, res) => {
console.log(JSON.stringify(req.user));
console.log("Router get user of type: " + (typeof req.user));
res.render('index', {
layout: false,
user: req.user,
});
});
输出将变为
{"_id":"629e3821bfb2869c42ac3c4b","username":"me","password":"123"}
Router get user of type: object
将req.user
转换为.username
如下,
app.get('/', (req, res) => {
console.log(req.user.username);
console.log("Router get user of type: " + (typeof req.user));
res.render('index', {
layout: false,
user: req.user,
});
});
我收到了错误,
TypeError: Cannot read properties of undefined (reading 'username')
at /Users/Wei/github/play-js/express/authentication/src/app.js:87:24
但是当我在模板文件中使用user.username
时,它没有显示用户名。
<body>
{{#if user}}
<h1>WELCOME BACK {{user.username}}</h1>
{{/if}}
</body>
但是,当我替换{{user.username}}}
by {{user}}
时,user
对象已正确打印,
<body>
{{#if user}}
<h1>WELCOME BACK {{user}}</h1>
{{/if}}
</body>
WELCOME BACK { _id: new ObjectId("629e3821bfb2869c42ac3c4b"), username: 'me', password: '123' }
但是根据the Handlebars Doc, Handlebars expression CAN be dot-separated paths.
那么这里有什么问题?
这是我如何设置express
服务器和passport
身份验证的完整代码,
// connect to MongoDB
const mongoDB = process.env.DB_URI;
mongoose.connect(mongoDB);
const db = mongoose.connection;
db.on('error', console.error.bind(console), 'MongoDB connection error');
// Schema & Model
const userSchema = new Schema({
username: {
type: String,
required: true,
},
password: {
type: String,
required: true,
}
});
const User = mongoose.model('User', userSchema);
// Express server
const app = express();
app.set('views', path.join(__dirname, 'views'));
const eh = handlebars.create(); // ExpressHandlebars instance
app.engine('handlebars', eh.engine); // register the engine() function
app.set('view engine', 'handlebars');
// Middleware
app.use(morgan('dev')); // logger
app.use(session({
secret: 'cats',
resave: false,
saveUninitialized: true,
}));
app.use(passport.initialize());
app.use(passport.session()); // this middleware will set cookie in client computer for each session.
app.use(express.urlencoded({
extended: false,
}));
// Verify username & password in our database
// Register the LocalStrategy to the passport.
passport.use(
new LocalStrategy(function verify(username, password, done) {
User.findOne({username: username}, (err, user) => {
if (err) return done(err);
if (!user) return done(null, false, {message: 'Incorrect username'});
if (user.password !== password) return done(null, false, {message: 'Incorrect password'});
return done(null, user);
});
})
);
// Only store user._id in the cookie.
passport.serializeUser(function(user, done) {
console.log(`serialize: ${user._id}`);
done(null, user._id);
});
// Get the user object from database by searching user._id.
passport.deserializeUser(function(_id, done) {
console.log(`deserialize search for: ${_id}`);
User.findById(_id, function(err, user) {
console.log(`deserialization find user: ${user}`);
done(err, user);
});
});
// router
app.get('/', (req, res) => {
console.log(JSON.stringify(req.user));
console.log("Router get user of type: " + (typeof req.user));
res.render('index', {
layout: false,
user: req.user,
});
});
app.post('/log-in', passport.authenticate('local', {
successRedirect: '/',
failureRedirect: '/',
}));
After authentication (with passport
module), a template was rendered with the req.user
object as follow,
app.get('/', (req, res) => {
console.log(`Router get user: ${req.user}`);
console.log("Router get user of type: " + (typeof req.user));
res.render('index', {
layout: false,
user: req.user,
});
});
I checked the req.user
by console.log
, and the user
object was printed as expected,
Router get user: {
_id: new ObjectId("629e3821bfb2869c42ac3c4b"),
username: 'me',
password: '123'
}
The second console.log
showed the type of req.user
is object
,
Router get user of type: object
After convert the req.user
to a string
,
app.get('/', (req, res) => {
console.log(JSON.stringify(req.user));
console.log("Router get user of type: " + (typeof req.user));
res.render('index', {
layout: false,
user: req.user,
});
});
the output became,
{"_id":"629e3821bfb2869c42ac3c4b","username":"me","password":"123"}
Router get user of type: object
If I further log req.user.username
as follow,
app.get('/', (req, res) => {
console.log(req.user.username);
console.log("Router get user of type: " + (typeof req.user));
res.render('index', {
layout: false,
user: req.user,
});
});
I got the error,
TypeError: Cannot read properties of undefined (reading 'username')
at /Users/Wei/github/play-js/express/authentication/src/app.js:87:24
But when I used user.username
in the template file, it didn't show the username.
<body>
{{#if user}}
<h1>WELCOME BACK {{user.username}}</h1>
{{/if}}
</body>
But when I replace the {{user.username}}
by {{user}}
, the user
object was printed correctly,
<body>
{{#if user}}
<h1>WELCOME BACK {{user}}</h1>
{{/if}}
</body>
WELCOME BACK { _id: new ObjectId("629e3821bfb2869c42ac3c4b"), username: 'me', password: '123' }
But according to the Handlebars Doc, Handlebars expression CAN be dot-separated paths.
So what's the problem here?
Here's the complete code how I set up the express
server and passport
authentication,
// connect to MongoDB
const mongoDB = process.env.DB_URI;
mongoose.connect(mongoDB);
const db = mongoose.connection;
db.on('error', console.error.bind(console), 'MongoDB connection error');
// Schema & Model
const userSchema = new Schema({
username: {
type: String,
required: true,
},
password: {
type: String,
required: true,
}
});
const User = mongoose.model('User', userSchema);
// Express server
const app = express();
app.set('views', path.join(__dirname, 'views'));
const eh = handlebars.create(); // ExpressHandlebars instance
app.engine('handlebars', eh.engine); // register the engine() function
app.set('view engine', 'handlebars');
// Middleware
app.use(morgan('dev')); // logger
app.use(session({
secret: 'cats',
resave: false,
saveUninitialized: true,
}));
app.use(passport.initialize());
app.use(passport.session()); // this middleware will set cookie in client computer for each session.
app.use(express.urlencoded({
extended: false,
}));
// Verify username & password in our database
// Register the LocalStrategy to the passport.
passport.use(
new LocalStrategy(function verify(username, password, done) {
User.findOne({username: username}, (err, user) => {
if (err) return done(err);
if (!user) return done(null, false, {message: 'Incorrect username'});
if (user.password !== password) return done(null, false, {message: 'Incorrect password'});
return done(null, user);
});
})
);
// Only store user._id in the cookie.
passport.serializeUser(function(user, done) {
console.log(`serialize: ${user._id}`);
done(null, user._id);
});
// Get the user object from database by searching user._id.
passport.deserializeUser(function(_id, done) {
console.log(`deserialize search for: ${_id}`);
User.findById(_id, function(err, user) {
console.log(`deserialization find user: ${user}`);
done(err, user);
});
});
// router
app.get('/', (req, res) => {
console.log(JSON.stringify(req.user));
console.log("Router get user of type: " + (typeof req.user));
res.render('index', {
layout: false,
user: req.user,
});
});
app.post('/log-in', passport.authenticate('local', {
successRedirect: '/',
failureRedirect: '/',
}));
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
在@phil的帮助下,我们在
deserializeuser()
函数中找到了错误。Passport.Deserializeuser()
简单地提取user._id
存储在cookie中,然后搜索整个user
来自mongodb
的对象,最近将设置为我们的req.user
。问题是
user.findbyid()
返回 mongoose文档
对象,它没有自己的
用户名
属性。我们需要的是一个普通的JavaScript对象。我们可以通过在
findbyid()
函数后立即启用精益
选项来实现这一目标。With the help of @Phil, we found the bug in
deserializeUser()
function.passport.deserializeUser()
simply extractsuser._id
stored in cookies, and search for entireuser
object fromMongoDB
, which will be lately set as ourreq.user
.The problem is that
User.findById()
return a mongooseDocument
object, which doesn't have its ownusername
property.What we need here is a plain javascript object. We can achieve that by enable the
lean
option right after thefindById()
function.