Проверка внешнего интерфейса, позволяющая пользователю сбросить пароль, только если токен действителен - PullRequest
0 голосов
/ 21 апреля 2020

В моем приложении есть функция сброса пароля, и у меня возникают проблемы с проверкой токена во внешнем интерфейсе. Так, например, когда пользователь получает ссылку в электронном письме, щелкает ее и перенаправляет на компонент ResetPasswordForm, который, по сути, является формой. Теперь я хочу, чтобы ResetPasswordForm только показывал / загружал, если токен проверен, в противном случае нет. Итак, как мне добиться этого?

Вот поток.

Из компонента ForgotPasswordForm пользователь вводит электронную почту и отправляет. Запрос приходит к конечной точке

router.post("/forgot-password", emailController.createOneTimeTokenAndSendMail)

ForgotPasswordForm. js

  handleSubmit = (e) => {
    e.preventDefault()
    const { email } = this.state
    axios
      .post("http://localhost:3000/api/v1/users/forgot-password", { email })


    //rest of the code
   }
  createOneTimeTokenAndSendEMail: async (req, res) => {
    const { email } = req.body 
    try {
      const user = await User.findOne({ email })
      if (!user) {
        return res.status(404).json({ error: "No user with that email" })
      }
      const hashedPassword = user.password
      const createdAt = user.createdAt
      const userId = user._id
      const secret = hashedPassword + "-" + createdAt //creating a secret this way makes it unique
      const token = jwt.sign({ userId }, secret, {
        expiresIn: 60,
      })
      const url = getResetPasswordURL(user, token) //one-time url with the userId and token embedded to it
      const emailTemplate = forgotPasswordTemplate(user, url) //an email template conataining the complete url 
      transporter.sendMail(emailTemplate, (err, info) => { //sending a mail template to the user
        if (err) {
          res.status(500).json({ error: err })
        }
        res.status(200).json({ info: info.response })
      })
    } catch (error) {
      console.log(error)
    }
  }

Теперь пользователь получает электронное письмо с ссылка (со встроенным в нее userId и токеном)

http://localhost:3000/reset-password/5e9d5b3e92ce57540705e6ff/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiI1ZTlkNWIzZTkyY2U1NzU0MDcwNWU2ZmYiLCJpYXQiOjE1ODc0NjIyNDUsImV4cCI6MTU4NzQ2MjMwNX0.z_P96H9tCuzMnmryNMNhKZN-LRQlwdR-bybCrNZocpU

Теперь пользователь нажимает на ссылку и ожидает, что ResetPasswordForm отобразится. Здесь я хочу показать страницу, только если токен проверен. Вот что я сделал.

Это обработчик отправки ResetPasswordForm, который достигает конца

router.get("/reset-password/:userId/:token", emailController.resetPassword)

ResetPasswordForm. js

  handleSubmit = (e) => {
    e.preventDefault()
    const { userId, token } = this.props.match.params
    const { password } = this.state
    axios
      .post(
        `http://localhost:3000/api/v1/users/reset-password/${userId}/${token}`,
        { password }
      )

     //rest of the code
    }
resetPassword: (req, res) => {
    const { userId, token } = req.params
    const password = req.body.password //password coming from the form the user has entered into
    User.findOne({ _id: userId }, (err, user) => { //find user by id
      if (err) console.log(err)
      const secret = user.password + "-" + user.createdAt //again, using the same secret(used above) to decode the token
      const payload = jwt.decode(token, secret) //decoding token using user's current password hash and createdAt value as a secret, which makes the secret very secure
      if (payload.userId == user.id) {
        bcrypt.genSalt(10, (err, salt) => {
          if (err) console.log(err)
          bcrypt.hash(password, salt, (err, hash) => { //hash the password coming in the body
            if (err) console.log(err)
            User.findOneAndUpdate( { _id: userId }, { password: hash }, (user, err) => { //find user and update the password field with a new hash OR replacing old password hash with a new hash
                if (err) console.log(err)
                res.status(202).json("password changed")
                receiveConfirmationEmail(userId) // function which sends a confirmation mail
              }
            )
          })
        })
      }
    })
  }

Я хотел бы знать, как мне показать компонент ResetPasswordForm только на основе проверки токена. Вот ссылка для двух ForgotPasswordForm и ResetPasswordForm. Я избегал вставлять здесь весь код, чтобы избежать путаницы


Кроме того, я хотел бы знать, чтобы изменить функцию контроллера resetPassword. Это выглядит очень плохо.

1 Ответ

0 голосов
/ 21 апреля 2020
  1. Визуализация страницы забытого пароля без отображения элементов управления сбросом пароля
  2. Тем временем проверьте токен сброса на сервере, если он действителен и не истек
  3. Если токен действителен, покажите сброс пароля Средства управления
  4. Снова отправьте маркер сброса с новым паролем, снова проверьте токен сброса на стороне сервера, чтобы проверить, исходит ли он от предполагаемого «пользователя».
  5. Удалить / аннулировать маркер сброса
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...