【问题标题】:Forgot password functionality using NodeJs/Knex/Nodemailer and it is not working properly忘记使用 NodeJs/Knex/Nodemailer 的密码功能并且无法正常工作
【发布时间】:2021-01-06 23:17:41
【问题描述】:

注意:这是我第一次发帖,如果您有任何反馈,请告诉我

目标:我正在构建一些端点,让用户在忘记密码时重置密码。流程如下所示:

  1. 用户不知道密码,所以点击忘记密码。
  2. 用户输入电子邮件并点击发送
  3. 用户收到带有重置密码链接的电子邮件。点击链接并被重定向以输入新密码。
  4. 他们点击“保存”并被重定向到登录以使用新密码登录

我正在使用 Insomnia 来测试端点。

有效的方法:

  • 在提供重置密码的电子邮件时,Nodemailer 会发送一封电子邮件。
  • 更新密码时,它会显示“密码已更新”并给出 200 状态。

错误:

  • 在尝试使用新密码登录后,它没有保存到数据库中。只有旧密码才能让您重新登录。

我尝试过的事情:

  • 我尝试更改我的 user.model 以使用我的 findByEmail 函数,但遇到了一些奇怪的错误,这让我陷入了困境。
  • 我尝试通过控制台记录很多东西,看看是否可以追踪路径。
  • 我尝试更改 user.update 函数,但无法使其正常工作。

这是我的代码: 任何指导将不胜感激。如果您需要查看任何其他文件,请告诉我。

忘记密码.js

const router = require('express').Router();
const crypto = require('crypto')
const User = require('../models/users.model')
const nodemailer = require('nodemailer')

router.post('/forgotpassword', (req, res) => {
  let {
    email
  } = req.body
  console.log(req.body)
  // if (req.body.email === '') {
  //   res.status(400).json({ message: 'Email is required'})
  // } console.error(req.body.email)
  User.findBy({
      email
    })
    .first()
    .then(user => {
      if (user === null) {
        res.status(403).json({
          message: 'Email not in db'
        })
      } else {
        const token = crypto.randomBytes(20).toString('hex')
        User.update({
          resetPasswordToken: token,
          resetPasswordExpires: Date.now() + 3600000,
        })
 
        const transporter = nodemailer.createTransport({
          service: 'gmail',
          auth: {
            user: `${process.env.EMAIL_USER}`,
            pass: `${process.env.EMAIL_PASS}`
          }
        })
        

        const mailOptions = {
          from: `${process.env.EMAIL_USER}`,
          to: `${user.email}`,
          subject: '[Promoquo] Reset Password Link',
          text: 'You are receiving this because you (or someone else) have requested the reset of the password for your account.\n\n' +
            'Please click on the following link, or paste this into your browser to complete the process within one hour of receiving it:\n\n' +
            `http://localhost:5000/reset/${token}\n\n` +
            'If you did not request this, please ignore this email and your password will remain unchanged.\n',
        }
        transporter.sendMail(mailOptions, (err, res) => {
          if (err) {
            console.log('ERROR coming from forgot.password js and it sucks', err)
          } else {
            console.log('here is the res', res)
            res.status(200).json({
              message: 'recovery email sent hell yes'
            })
          }
        })
      }
      res.status(200).json({
        message: 'Reset password email has been sent WOOHOO ????'
      }) 
    })
    .catch(error => {
      res.status(500).json({
        message: 'ERROR on last catch forgotpassword.js, likely no user exists',
        error
      })
      console.log(error)
    })
})

module.exports = router

更新密码.js

const router = require('express').Router();
const passport = require('passport')
const bcrypt = require('bcrypt')
const User = require('../models/users.model')

const BCRYPT_SALT_ROUNDS = 12

router.put('/updatePasswordViaEmail', (req, res) => {
  User.find({
    where: {
      username: req.body.username,
      resetPasswordToken: req.body.resetPasswordToken,
      resetPasswordExpires: Date.now() + 3600000,
    }
  })
  .then(user => {
    if (user == null) {
      console.error('password reset link has expired')
      res.status(403).json({ message: 'Password reset link is invalid or has expired' })
    } else if (user != null) {
      console.log('user exists in db')
      bcrypt.hash(req.body.password, BCRYPT_SALT_ROUNDS)
      .then(hashedPassword => {
        User.update({
          password: hashedPassword,
          resetPasswordToken: null,
          resetPasswordExpires: null,
        })
      })
      .then(() => {
        console.log('log for THEN updating password')
        res.status(200).json({ message: 'password updated' })
      })
    } else {
      console.error('no user exists in db to update')
      res.status(401).json({ message: 'no user exists in db to update'})
    }
  })
})

module.exports = router

Users.model.js

const db = require('../dbConfig')

module.exports = {
  add,
  find,
  findBy,
  findById,
  findByEmail,
  findByType,
  update
};

function find() {
  return db('users').select('id', 'username', 'email', 'password');
}

function findBy(filter) {
  return db('users').where(filter);
}

async function add(user) {
  const [id] = await db('users').insert(user);

  return findById(id);
}

function findById(id) {
  return db('users').where({ id }).first();
}

function findByEmail(email) {
  return db('users').where({ email }).first();
}

function findByType(type) {
  return db('users').where({ type }).first();
}

function update(changes, id) {
  return db('users').where({ id }).update(changes)
}

20200913211559_users.js(这是表格)

exports.up = function(knex) {
  return knex.schema.createTable('users', tbl => {
    tbl.increments();
    tbl.string('firstname', 30).notNullable();
    tbl.string('lastname', 30).notNullable();
    tbl.string('username', 30).notNullable()
    tbl.string('email', 50).notNullable()
    tbl.string('password', 128).notNullable();
    tbl.string('type').notNullable();
    tbl.boolean('confirmed').defaultTo('false');
    tbl.string('resetPasswordToken');
    tbl.date('resetPasswordExpires');
  })
};

exports.down = function(knex) {
  return knex.schema.dropTableIfExists('users')
};

【问题讨论】:

    标签: javascript node.js knex.js nodemailer


    【解决方案1】:

    您的User.update() 行没有运行(您需要将它们的承诺返回到承诺链中,或者挂钩到它们的回调中)。 async/await 是您在这里避免“回调地狱”的朋友。

    const user = await User.find({
      where: {
        username: req.body.username,
        resetPasswordToken: req.body.resetPasswordToken,
        resetPasswordExpires: Date.now() + 3600000,
      }
    })
    if (!user) { /* ... */ }
    const token = crypto.randomBytes(20).toString('hex')
    await User.update({ // await here!
      resetPasswordToken: token,
      resetPasswordExpires: Date.now() + 3600000,
    })
    

    【讨论】:

    • 非常感谢您的回复。我将尝试添加异步/等待,看看会发生什么。您能否通过在 MongoDB 中使用未经处理的正文参数来澄清您的意思。我没有使用 MongoDB,我使用的是 SQlite3。感谢你的帮助!我在这方面绝对是新手。已经编码了大约一年。
    • @RyanRenteria 没问题。使用 SQlite3 我认为你很好——我错误地认为是 MongoDB,抱歉。
    • 哦,好吧,明白了!非常感谢你的帮助。我今天将对此进行研究,看看会发生什么。 :)
    • 其实还有一个问题。我需要在 forgot.password.js 和 update.password.js 中都使用 async/await,还是只使用某个?
    • 你应该await all 数据库操作。这会将结果提交给数据库,因此您知道 (1) 数据库成功应用了它,没有架构违规阻止它保存等。 (2) 没有并发问题,例如您无法查询用户并获取陈旧数据。
    猜你喜欢
    • 2019-10-12
    • 2013-12-09
    • 2011-10-19
    • 2011-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-27
    • 2010-10-06
    相关资源
    最近更新 更多