已解决:我的代码在node js中解密邮件激活令牌后无法加密密码保存在mongoDB中,如何解决?

问题描述

我正在尝试通过 MERN 实现 jwt 身份验证,并且在 nodejs 中我使用电子邮件激活链接用户电子邮件和密码保存在 mongodb 中。这是我注册用户和激活用户的工作示例。我正在使用 sendgrid 发送电子邮件

//for email verification test

signup = async (req,res) => {
  const { username,email,password,passwordCheck,displayName } = req.body;
    //validate
    if (!username || !email || !password || !passwordCheck)
      return res.status(400).json({
        msg: "not all fields have been entered.",});
    if (password.length < 8)
      return res.status(400).json({
        msg: "The password needs to be at least 8 characters long.",});
    if (password !== passwordCheck)
      return res
        .status(400)
        .json({ msg: "Enter the same password twice for verification." });
    const existingUser = await User.findOne({ email: email });
    if (existingUser)
      return res
        .status(400)
        .json({ msg: "An account with this email already exists." });
    const existingUserName = await User.findOne({ username: username });
    if (existingUserName)
      return res
        .status(400)
        .json({ msg: "An account with this username already exists." });
    if (!displayName) displayName = email;

    const token = jwt.sign(
      { username,displayName },process.env.JWT_SECRET,{expiresIn:'1000m'}
    );
    const msg = {
      to: email,//receiver's email
      from: "no-reply@test.com",// Change to your verified sender
      subject: `Email verification link ${displayName}`,text: "testing from local",html: `<h2>Hi ${displayName}</h2> <br/>sends a message for verification test: http://localhost:3000/authentication/activate/${token}</p> <br/><p>Have a nice day</p>`,};
    sgMail.setApiKey(process.env.SENDGRID_SECRET_API);
    sgMail
      .send(msg)
      .then((result) => {
        res.json({ message: "Email activation link has been sent" });
      })
      .catch((error) => {
        console.error(error);
        res.status(500).json("Error");
      });

}
router.post("/register",signup);

userActivation = (req,res)=>{
    const { token } = req.body;
  if(token){
    jwt.verify(token,function(err,decodetoken){
      if(err){
        return res.status(400).json({error:'Incorrect or expired link.'})
      }
    const { username,displayName }=decodetoken;
    
    const newUser = new User({
      username,displayName,});
    newUser.save((err,success)=>{
      if(err){
        console.log("Error in signup with account activation",err)
        return res.status(400).json({error:"Error activating account"})
      }
      res.json({
        message:"signup Success!!"
      })
    });
     
  
    } );
  } else{
    return  res.json({error:"Something went wrong"})
  } 

}

router.post("/email-activate",userActivation)

在使用邮递员使用激活密钥保存用户时,在 mongodb 中,密码以纯文本格式保存。由于安全问题,我不希望它以纯文本格式保存。我希望它以加密方式保存并尝试使用以下代码

userActivation = async (req,res) => {
    const { token } = req.body;
    if (token) {
        jwt.verify(token,function (err,decodetoken) {
            if (err) {
                return res.status(400).json({ error: "Incorrect or expired link." });
            }
            const { username,displayName } = decodetoken;
            console.log(password)
            User.findOne({ email }).exec((err,user) => {
                if (user) {
                    return res.status(400).json({ error: "Username with this email exists." })
                }
                const salt = bcrypt.genSalt();
                bcrypt.hash(password,salt,(err,passwordHash)=>{
                    const newUser = new User({
                        username,password: passwordHash,});
                     console.log(password) 
                    console.log(passwordHash)
                    newUser.save((err,success) => {
                        if (err) {
                            console.log("Error in signup with account activation",err);
                            return res.status(400).json({ error: "Error activating account" });
                        }
                        res.json({
                            message: "signup Success!!",});
                    })
                })
            })
        })
    }
}   

当我启动服务器并尝试通过邮递员使用激活密钥登录时,它会向我发送激活链接。当我尝试通过激活链接中的邮递员发送发布请求时,邮递员显示 404 状态并显示错误激活帐户”,并且节点索引显示以下错误

        The server has started on port: 5000
    MongoDB connected
    **the real password is showing undecoded**
**the real password is showing undecoded**
    undefined
    Error in signup with account activation Error: user validation Failed: password: Path `password` is required.
        at ValidationError.inspect (C:\Myfiles\Reactjs\Projects\test-projects\node_modules\mongoose\lib\error\validation.js:47:26) 
        at formatValue (internal/util/inspect.js:731:31)
        at inspect (internal/util/inspect.js:295:10)
        at formatWithOptionsInternal (internal/util/inspect.js:1958:40)
        at formatWithOptions (internal/util/inspect.js:1842:10)
        at Object.value (internal/console/constructor.js:306:14)
        at Object.log (internal/console/constructor.js:341:61)
        at C:\Myfiles\Reactjs\Projects\test-projects\routes\userRouter.js:243:37
        at C:\Myfiles\Reactjs\Projects\test-projects\node_modules\mongoose\lib\model.js:4863:16
        at C:\Myfiles\Reactjs\Projects\test-projects\node_modules\mongoose\lib\helpers\promiSEOrCallback.js:16:11
        at C:\Myfiles\Reactjs\Projects\test-projects\node_modules\mongoose\lib\model.js:4886:21
        at C:\Myfiles\Reactjs\Projects\test-projects\node_modules\mongoose\lib\model.js:500:16
        at C:\Myfiles\Reactjs\Projects\test-projects\node_modules\kareem\index.js:247:48
        at next (C:\Myfiles\Reactjs\Projects\test-projects\node_modules\kareem\index.js:168:27)
        at next (C:\Myfiles\Reactjs\Projects\test-projects\node_modules\kareem\index.js:170:9)
        at Kareem.execPost (C:\Myfiles\Reactjs\Projects\test-projects\node_modules\kareem\index.js:218:3) {
      errors: {
        password: ValidatorError: Path `password` is required.
            at validate (C:\Myfiles\Reactjs\Projects\test-projects\node_modules\mongoose\lib\schematype.js:1256:13)
            at C:\Myfiles\Reactjs\Projects\test-projects\node_modules\mongoose\lib\schematype.js:1239:7
            at Array.forEach (<anonymous>)
            at SchemaString.SchemaType.dovalidate (C:\Myfiles\Reactjs\Projects\test-projects\node_modules\mongoose\lib\schematype.js:1184:14)
            at C:\Myfiles\Reactjs\Projects\test-projects\node_modules\mongoose\lib\document.js:2502:18
            at processticksAndRejections (internal/process/task_queues.js:75:11) {
          properties: [Object],kind: 'required',path: 'password',value: undefined,reason: undefined,[Symbol(mongoose:validatorError)]: true
        }
      },_message: 'user validation Failed'
    }

根据上面的尝试,代码无法对密码进行加密,因此无法将其保存在mongodb中。我在编码密码时做错了什么? 那么我该如何解决呢?

提前谢谢

解决方法

const passwordHash =  bcrypt.hash(password,salt);
Here bcrypt.hash returning promise either your can use async/await or use .then().



            userActivation = async (req,res) => {
        const { token } = req.body;
        if (token) {
            jwt.verify(token,process.env.JWT_SECRET,function (err,decodeToken) {
                if (err) {
                    return res.status(400).json({ error: "Incorrect or expired link." });
                }
                const { username,email,password,displayName } = decodeToken;
                console.log(password);
                User.findOne({ email }).exec((err,user) => {
                    if (user) {
                        return res.status(400).json({ error: "Username with this email exists." })
                    }
//Use genSaltSync when you donot want to use await or your can use await bcrypt.genSalt()
                    const salt = bcrypt.genSaltSync(10);
                    bcrypt.hash(password,salt,(err,passwordHash)=>{
                        const newUser = new User({
                            username,password: passwordHash,displayName,});
                        newUser.save((err,success) => {
                            if (err) {
                                console.log("Error in signup with account activation",err);
                                return res.status(400).json({ error: "Error activating account" });
                            }
                            res.json({
                                message: "signup Success!!",});
                        })
                    })
                })
            })
        }
    }

Try this code once just put await before bcrypt and made function async.