车把无法访问对象的属性

发布于 2025-02-04 19:27:44 字数 4758 浏览 3 评论 0原文

在身份验证(使用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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

南街九尾狐 2025-02-11 19:27:44

在@phil的帮助下,我们在deserializeuser()函数中找到了错误。

// Get the user object from database by searching user._id.
passport.deserializeUser(function(_id, done) {
  User.findById(_id, function(err, user) {
    console.log(`deserialization find user: ${user}`);
    done(err, user);
  });
});

Passport.Deserializeuser()简单地提取user._id存储在cookie中,然后搜索整个user来自mongodb的对象,最近将设置为我们的req.user

问题是user.findbyid()返回 mongoose 文档对象,它没有自己的用户名属性。

我们需要的是一个普通的JavaScript对象。我们可以通过在findbyid()函数后立即启用精益选项来实现这一目标。

// Get the user object from database by searching user._id.
passport.deserializeUser(function(_id, done) {
  User.findById(_id, function(err, user) {
    console.log(`deserialization find user: ${user}`);
    done(err, user);
  }).lean(); // it returns a plain javascript object now
});

With the help of @Phil, we found the bug in deserializeUser() function.

// Get the user object from database by searching user._id.
passport.deserializeUser(function(_id, done) {
  User.findById(_id, function(err, user) {
    console.log(`deserialization find user: ${user}`);
    done(err, user);
  });
});

passport.deserializeUser() simply extracts user._id stored in cookies, and search for entire user object from MongoDB, which will be lately set as our req.user.

The problem is that User.findById() return a mongoose Document object, which doesn't have its own username property.

What we need here is a plain javascript object. We can achieve that by enable the lean option right after the findById() function.

// Get the user object from database by searching user._id.
passport.deserializeUser(function(_id, done) {
  User.findById(_id, function(err, user) {
    console.log(`deserialization find user: ${user}`);
    done(err, user);
  }).lean(); // it returns a plain javascript object now
});
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文