TypeError:无法读取 MEAN 堆栈中未定义的属性“_id”

Posted

技术标签:

【中文标题】TypeError:无法读取 MEAN 堆栈中未定义的属性“_id”【英文标题】:TypeError: Cannot read property '_id' of undefined in MEAN Stack 【发布时间】:2017-11-05 09:29:18 【问题描述】:

我想要完成的是当用户发送消息时在数据库中写入消息。我正在使用带有 angular-cli 的 MEAN 堆栈。

我收到的错误是:

TypeError: Cannot read property '_id' of undefined
    at JwtStrategy._verify (/Volumes/SSD/Documents/WebProjects/MEANTest/config/passport.js:11:38)
    at /Volumes/SSD/Documents/WebProjects/MEANTest/node_modules/passport-jwt/lib/strategy.js:110:26
    at /Volumes/SSD/Documents/WebProjects/MEANTest/node_modules/jsonwebtoken/verify.js:27:18
    at _combinedTickCallback (internal/process/next_tick.js:73:7)
    at process._tickCallback (internal/process/next_tick.js:104:9)

这是我用来查看是否有人能找出我做错了什么的所有代码。

Express 节点位于“/users”:

router.post('/newmessages', passport.authenticate('jwt', session: false), function(req, res, next)

var msgID = getMessageID(req.body.user.username);

  let newMessage = Message(
    createdBy:req.body.message.createdBy,
    recipients:req.body.message.recipients,
    dateCreated:getTodayDate(),
    subject:req.body.message.subject,
    message:req.body.message.message,
    read: false,
    previousMessage:req.body.message.previousMessage,
    nextMessage:req.body.message.nextMessage,
    messageID:msgID
  );

  console.log(newMessage);

  Message.checkMessageID(newMessage, function(err, isFound)
    if(err) throw err;
    if(isFound)
    
      newMessage.messageID = getMessageID(req.body.username);
    
    else
    
      Message.createMessage(newMessage, function(err, isCreated)
        if(err) throw err;
        if(isCreated)
        
          var token = jwt.sign(req.body, config.secret, 
            expiresIn: 604800 // A week worth of seconds
          );

          res.json(
            success: true,
            token: "JWT " + token,
            user: 
              id: req.body._id,
              name: req.body.name,
              username: req.body.username,
              email: req.body.email
            ,
            msg: "Your password has been changed."
          );
        
        else
        
          var token = jwt.sign(req.body, config.secret, 
            expiresIn: 604800 // A week worth of seconds
          );

          res.json(
            success: true,
            token: "JWT " + token,
            user: 
              id: req.body._id,
              name: req.body.name,
              username: req.body.username,
              email: req.body.email
            ,
            msg: "Your password has been changed."
          );
        
      );
    
  );
);

PassportJS

var JwtStrategy = require('passport-jwt').Strategy;
var ExtractJwt = require('passport-jwt').ExtractJwt;
var User = require('../models/user');
var config = require('./database');

module.exports = function (passport)
  let opts = ;
  opts.jwtFromRequest = ExtractJwt.fromAuthHeader();
  opts.secretOrKey = config.secret;
  passport.use(new JwtStrategy(opts, function(jwt_payload, done)
    User.getUserByID(jwt_payload._doc._id, function(err, user)
      if(err) 
        return done(err, false);
      
      if(user)
        return done(null, user);
      
      else
        return done(null, false);
      
    );
  ));
;

Mongoose 架构和代码:

var mongoose = require('mongoose');
var config = require('../config/messages');

// Message Schema
var messageSchema = mongoose.Schema(
  createdBy: 
    type: String,
    required: true
  ,
  recipients:
    type: String,
    required: true
  ,
  dateCreated: 
    type: String,
    required: true
  ,
  subject: 
    type: String,
    required: true
  ,
  message: 
    type: String,
    required: true
  ,
  previousMessage: 
    type: String,
    required: true
  ,
  nextMessage: 
    type: String,
    required: true
  ,
  read: 
    type:Boolean,
    required: true
  ,
  messageID: 
    type: String,
    required: true
  
);

var secondConn = mongoose.createConnection(config.database);

// On Connection
secondConn.on('connected', function()
    console.log("Connected to database "+ config.database);
);

// On Error
secondConn.on('error', function(err)
    console.log("Database Error " + err);
);

var Messages = module.exports = secondConn.model('Messages', messageSchema);

module.exports.getAllUserMessages = function(user, callback)
  var query = createdBy: user;

  Messages.find(query, callback);
;

module.exports.getAllRecpMessages = function(user, callback)
  var query = recipients: user;

  Messages.find(query, callback);
;

module.exports.deleteMessage = function(list, callback)
  var query, i;

  for(i = 0; i < list.length; i++)
  
      query =  messageID: list[i].messageID;
      Messages.remove(query, function(err)
      );
  
;

module.exports.createMessage = function(message, callback)
  message.save(function(err, doc)
    if(err) throw err;
    if(doc === null)
    
      callback(null, false);
    
    else
    
      callback(null, true);
    
  );
;

// Returns false if no other message has the same ID
module.exports.checkMessageID = function(message, callback)
  var query = messageID: message.messageID;

  Messages.findOne(query, function(err, message)
    if(err) throw err;
    if(message === null)
    
      callback(null, false);
    
    else
    
      callback(null, true);
    
  );
;

'/users/messages' 的 Angular 打字稿:

import  Component, OnInit  from '@angular/core';
import  AuthService  from '../../services/auth.service';
import  Router  from '@angular/router';
import  FlashMessagesService  from 'angular2-flash-messages';

@Component(
  selector: 'app-messages',
  templateUrl: './messages.component.html',
  styleUrls: ['./messages.component.css']
)
export class MessagesComponent implements OnInit 
  createdBy: String;
  recipients: String;
  subject: String;
  message: String;
  previousMessage: String;
  nextMessage: String;
  user: Object;

  constructor(private authService: AuthService,
    private router: Router,
    private flashMessage: FlashMessagesService
    )  

  ngOnInit() 
    this.authService.getProfile().subscribe(profile => 
      this.user = profile.user;
      this.createdBy = profile.user.username;
    ,
    err => 
      console.log(err);
      return false;
    );
  

// Need to create Message object and pass to Back End
  newMessage()
    const newMessage = 
      createdBy: this.createdBy,
      recipients: this.recipients,
      subject: this.subject,
      message: this.message,
      previousMessage: " ",
      nextMessage: " "
    

    this.authService.newMessage(this.user, newMessage).subscribe(data => 
      if(data.success)
        this.authService.storeUserData(data.token, data.user);
        console.log(data);
        this.router.navigate(['profile']);
      else
        console.log(data);
        this.router.navigate(['dashboard']);
      
    );
  

  getMessages()

    this.authService.getMessages(this.user).subscribe(data => 
      if(data.success)
        this.authService.storeUserData(data.token, data.user);
        this.router.navigate(['messages']);
        console.log(data);
      else
        this.router.navigate(['dashboard']);
      
    );
  

Angular 身份验证服务:

import  Injectable  from '@angular/core';
import  Http, Headers  from '@angular/http';
import 'rxjs/add/operator/map';
import  tokenNotExpired  from 'angular2-jwt';

@Injectable()
export class AuthService 
authToken: any;
user: any;
message: any;

  constructor(private http: Http)  

// Need to pass Message object to Front End
  newMessage(user, message)
    console.log(user.username + " " + message.createdBy);
    let headers = new Headers();
    this.loadToken();
    headers.append('Authorization', this.authToken);
    headers.append('Content-Type', 'application/json');
    var info = user, message;
    return this.http.post('/users/newmessages', user, headers: headers, body: info)
      .map(res => res.json());
  

  getMessages(user)
    let headers = new Headers();
    this.loadToken();
    headers.append('Authorization', this.authToken);
    headers.append('Content-Type', 'application/json');
    return this.http.post('/users/messages', user, headers: headers)
      .map(res => res.json());
  

  registerUser(user)
    let headers = new Headers();
    headers.append('Content-Type', 'application/json');
    return this.http.post('/users/register', user, headers: headers)
      .map(res => res.json());
  

  authenticateUser(user)
    let headers = new Headers();
    headers.append('Content-Type', 'application/json');
    return this.http.post('/users/authenticate', user, headers: headers)
      .map(res => res.json());
  

  changePassword(user)
    let headers = new Headers();
    this.loadToken();
    headers.append('Authorization', this.authToken);
    headers.append('Content-Type', 'application/json');
    return this.http.post('/users/changepassword', user, headers: headers)
      .map(res => res.json());
  

  getProfile()
    let headers = new Headers();
    this.loadToken();
    headers.append('Authorization', this.authToken);
    headers.append('Content-Type', 'application/json');
    return this.http.get('/users/profile', headers: headers)
      .map(res => res.json());
  

  storeUserData(token, user)
    localStorage.setItem('id_token', token);
    localStorage.setItem('user', JSON.stringify(user));
    this.authToken = token;
    this.user = user;
  

  loadToken()
    const token = localStorage.getItem('id_token');
    this.authToken = token;
  

  loggedIn()
    return tokenNotExpired('id_token');
  

  logout()
    this.authToken = null;
    this.user = null;
    localStorage.clear();
  

以防万一,这是我来自 Mongoose Schema 的部分用户模型:

var mongoose = require('mongoose');
var bcrypt = require('bcryptjs');
var config = require('../config/database');

// User Schema
var userSchema = mongoose.Schema(
  name: 
    type: String
  ,
  email:
    type: String,
    required: true
  ,
  username: 
    type: String,
    required: true
  ,
  password: 
    type: String,
    required: true
  ,
  verify: 
    type: Boolean,
    required: true
  
);

【问题讨论】:

看起来错误可能是在您的 PassportJS 设置代码中抛出的以下行:User.getUserByID(jwt_payload._doc._id, function(err, user)...。你能在那里console.log(jwt_payload) 确保它包含一个 _doc 键并且它包含一个 _id 键吗? 我在接受护照认证检查时忘记提到这适用于邮递员,但它从来没有从前到后工作过。 _doc 来自哪里? @LeandroRodrigues 你是什么意思? 你的问题,似乎在这里:jwt_payload._doc._id_doc 未定义。 _doc 值从何而来? 【参考方案1】:

哇,修好了!

在“/users/messages”的 Angular 打字稿中:

// Need to create Message object and pass to Back End
  newMessage()
    const newMessage = 
      createdBy: this.createdBy,
      recipients: this.recipients,
      subject: this.subject,
      message: this.message,
      previousMessage: " ",
      nextMessage: " "
    

    this.authService.newMessage(this.user, newMessage).subscribe(data => 
      if(data.success)
        this.authService.storeUserData(data.token, data.user); < Erased that line
        console.log(data);
        this.router.navigate(['profile']);
      else
        console.log(data);
        this.router.navigate(['dashboard']);
      
    );
  

TL;DR 解释,我传递了一个从后端提供的未定义的“数据”。我删除了标记的行以确保在发送消息后我没有存储用户数据......因为我不需要。

感谢所有帮助过我的人!

【讨论】:

【参考方案2】:

我遇到了同样的问题

只需 console.log jwt_payload 即可查看 _id 在哪里

在我的代码中我有jwt_payload.data._id

删除 .data 对我的情况有所帮助

【讨论】:

很高兴我帮助了你

以上是关于TypeError:无法读取 MEAN 堆栈中未定义的属性“_id”的主要内容,如果未能解决你的问题,请参考以下文章

TypeError:无法读取 null 的属性“标题”!平均堆栈

Nodejs Promise TypeError:无法读取未定义的属性'then'

React JS,Firebase,TypeError:无法读取未定义的属性“initializeApp”

TypeError:无法使用玩笑读取未定义的属性“原型”

TypeError:无法读取未定义 Passpor 错误的属性“名称”

无法读取未定义和未处理的承诺拒绝的属性“捕获”