В моем приложении есть функция сброса пароля, и у меня возникают проблемы с проверкой токена во внешнем интерфейсе. Так, например, когда пользователь получает ссылку в электронном письме, щелкает ее и перенаправляет на компонент 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
. Это выглядит очень плохо.