【问题标题】:Mongoose Schema.method() is not working, and showing an error messageMongoose Schema.method() 不起作用,并显示错误消息
【发布时间】:2021-01-20 22:49:52
【问题描述】:

我从用户那里获取密码输入并使用密码加密密码,然后保存到数据库中。这是我的代码,这里我将加密的密码存储到来自 userSchema 的 encry_password 属性中。但是,这给了我“this.securePassword”不是函数的错误。

const mongoose = require("mongoose");
const crypto = require("crypto");
const { v1: uuidv1 } = require("uuid");

const userSchema = new mongoose.Schema({
  name: {
    type: String,
    required: true,
    maxlength: 32,
    trim: true,
  },
  lastname: {
    type: String,
    maxlength: 32,
    trim: true,
  },
  email: {
    type: String,
    trim: true,
    required: true,
    unique: true,
  },
  usrinfo: {
    type: String,
    trim: true,
  },
  encry_password: {
    type: String,
    required: true
  },
  salt: String,
  role: {
    type: Number,
    default: 0,
  },
  purchases: {
    type: Array,
    default: [],
  },
}, { timestamps: true });


userSchema.virtual("password")
  .set((password) => {
    this._password = password;
    this.salt = uuidv1();
    this.encry_password = securePassword(password, uuidv1());
    console.log(this.encry_password);
  })
  .get(() => {
    return this._password;
  });

// const authenticate = function (plainPassword, encry_password) {
//   return securePassword(plainPassword) === encry_password;
//   };

const securePassword = function (plainPassword, salt) {
  if (!plainPassword) return "";
  try {
    return crypto.createHmac("sha256", salt).update(plainPassword).digest("hex");
  } catch (error) {
    return "";
  }
};


module.exports = mongoose.model("User", userSchema);

用户注册路径

exports.signup = (req, res) => {
    console.log(req.body);
    const user = new User(req.body);
    user.save((err, user) => {
        if (err) {
            console.log(err);
            res.status(400).json({
                err: "Note able to save the user in database"
            });
        } else {
            res.json(user);
        }
    });
};

【问题讨论】:

    标签: node.js mongodb mongoose mongoose-schema


    【解决方案1】:

    首先,在这种情况下你不应该使用virtual

    Virtuals

    虚拟是您可以获取和设置但不会持久保存到 MongoDB 的文档属性。 getter 可用于格式化或组合字段,而 setter 可用于将单个值分解为多个值以进行存储。

    但是在virtual范围内,this不能访问方法,你不能像你的方式访问方法,这是mongoose中方法使用的一个例子

      const Animal = mongoose.model('Animal', animalSchema);
      const dog = new Animal({ type: 'dog' });
    
      dog.findSimilarTypes((err, dogs) => {
        console.log(dogs); // woof
      });
    

    您可以查看method documantation:

    如果你只想以你的方式访问securePassword,你可以喜欢这个并完全删除方法mongoose,因为这不是使用method的地方:

    UserSchema.virtual("password")
      .set((password) => {
        this._password = password;
        this.salt = uuidv1();
        console.log("This is running");
        this.encry_password = securePassword(password, this.salt);
        console.log(encry_password);
      })
      .get(() => {
        return this._password;
      });
    
    const authenticate = function (plainPassword, encry_password) {
      return securePassword(plainPassword) === encry_password;
    };
    
    const securePassword = function (plainPassword, salt) {
      if (!plainPassword) return "";
      try {
        return crypto
          .createHmac("sha256", salt)
          .update(plainPassword)
          .digest("hex");
      } catch (error) {
        return "";
      }
    };
    

    如果你想创建authenticate service,改变你的方式,不要使用虚拟密码,使用pre save

    在将有关用户的信息保存到数据库之前,将完成此任务 检查pre documentation

    userSchema.pre("save", async function (next) {
      try {
        this.password = securePassword (plainPassword, salt);
      } catch (error) {
        console.log(error);
      }
    });
    

    创建哈希密码后保存信息如下:

    const userSchema = new mongoose.Schema({
        .
        .
        .
        password: { //convert encry_password to password
          type: String,
        }
        .
        .
        .
      }, { timestamps: true });
      //every time want to user save this method called
      userSchema.pre('save', function (next) {
        this.salt = uuidv1()
        this.password = securePassword(this.password, this.salt)
        next()
     })
     //for have a clean  routes, you can create a static methods
     userSchema.statics.Create = async (data) => {
        let model = new User(data); 
        let resUser = await model.save(); //save your user
        return resUser;
      };
    
      const securePassword = function (plainPassword, salt) {
        if (!plainPassword) return "";
        try {
          return crypto.createHmac("sha256", salt).update(plainPassword).digest("hex");
        } catch (error) {
          return "";
        }
      };
      
      let User  = mongoose.model("User", userSchema)
      module.exports = {User};
    

    像这样更改控制器:

    let {User} = require("./path of user schema")
    exports.signup = async (req, res) => {
      try {
        console.log(req.body);
        const user = await User.create(req.body); //create a user
        res.json(user);
      } catch (error) {
        console.log(err);
        res.status(400).json({
          err: "Note able to save the user in database",
        });
      }
    };
    

    注意:在 req.body 中,密码字段的名称应为password

    【讨论】:

    • 我运行了这段代码,它工作正常并且能够在 this.encry_password 属性中存储加密的密码。但是,问题是在 this.encry_password 属性中存储密码之前,空信息被保存在数据库中,这就是它抛出错误“this.encry_password is required”的原因。
    • 请将您的架构文件完全添加到问题中
    • 你应该改变你的方式,不要使用virtual,在virtual范围内不能访问带有this的架构字段,使用pre save
    • 我已经添加了我的整个架构文件,你现在可以查看
    • 您想创建一个带有哈希密码的用户吗?对吗?
    【解决方案2】:

    securePassword 函数的范围似乎是在 userSchema 中定义的,而您正试图在 userSchema.virtual 中调用它。

    【讨论】:

    • 你能帮我解决这个问题吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-17
    • 1970-01-01
    • 2012-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-30
    相关资源
    最近更新 更多