«Если рабочий хочет хорошо выполнять свою работу, он должен сначала заточить свои инструменты» — Конфуций, «Аналитики Конфуция. Лу Лингун»
титульная страница > программирование > Функция сброса пароля: использование OTP для сброса пароля

Функция сброса пароля: использование OTP для сброса пароля

Опубликовано 6 ноября 2024 г.
Просматривать:558

Password Reset Feature: Using OTP to Reset Password

Бэкэнд

2. Сброс пароля

Переходим к следующему API.

Вставьте /api/reset-password, req -> otp, email, новый пароль, res -> nocontent

// controllers/passwordReset.go
func ResetPassword(c *fiber.Ctx) error {
    type Input struct {
        OTP         string `json:"otp"`
        Email       string `json:"email"`
        NewPassword string `json:"new_password"`
    }

    var input Input

    err := c.BodyParser(&input)
    if err != nil {
        return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
            "error": "invalid data",
        })
    }

    // no input field should be empty
    if input.OTP == "" || input.Email == "" || input.NewPassword == "" {
        return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
            "error": "invalid data",
        })
    }

    // TODO: check redis for otp and update password

    return c.SendStatus(fiber.StatusNoContent)
}

Добавление маршрута

// routes/routes.go
api.Put("/reset-password", controllers.ResetPassword)

Теперь мне нужны две функции:

  1. VerifyOTP -> input = otp, электронная почта; вывод = ошибка (если есть)
  2. UpdatePassword -> input = электронная почта, пароль; вывод = ошибка (если есть)
// utils/passwordReset.go
func VerifyOTP(otp string, email string, c context.Context) (error, bool) {
    key := otpKeyPrefix   email

    // get the value for the key
    value, err := config.RedisClient.Get(c, key).Result()
    if err != nil {
        // the following states that the key was not found
        if err == redis.Nil {
            return errors.New("otp expired / incorrect email"), false
        }

        // for other errors
        return err, true
    }

    // compare received otp's hash with value in redis
    err = bcrypt.CompareHashAndPassword([]byte(value), []byte(otp))
    if err != nil {
        return errors.New("incorrect otp"), false
    }

    // delete redis key to prevent abuse of otp
    err = config.RedisClient.Del(c, key).Err()
    if err != nil {
        return err, true
    }

    return nil, false
}

func UpdatePassword(email string, password string, c context.Context) error {
    users := config.DB.Collection("users")

    // hash the password
    hashedPassword, _ := bcrypt.GenerateFromPassword([]byte(password), 10)

    // update the password
    update := bson.M{
        "$set": bson.M{
            "password": hashedPassword,
        },
    }
    _, err := users.UpdateByID(c, email, update)
    if err != nil {
        return err
    }

    return nil
}

Теперь мне нужно объединить их оба в контроллере. Я использую bool из функции VerifyOTP, чтобы указать, является ли ошибка внутренней ошибкой или это результат ввода.

// controllers/passwordReset.go
func ResetPassword(c *fiber.Ctx) error {
    type Input struct {
        OTP         string `json:"otp"`
        Email       string `json:"email"`
        NewPassword string `json:"new_password"`
    }

    var input Input

    err := c.BodyParser(&input)
    if err != nil {
        return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
            "error": "invalid data",
        })
    }

    // no input field should be empty
    if input.OTP == "" || input.Email == "" || input.NewPassword == "" {
        return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
            "error": "invalid data",
        })
    }

    // check redis for otp
    err, isInternalErr := utils.VerifyOTP(input.OTP, input.Email, c.Context())
    if err != nil {
        var code int
        if isInternalErr {
            code = fiber.StatusInternalServerError
        } else {
            code = fiber.StatusUnauthorized
        }

        return c.Status(code).JSON(fiber.Map{
            "error": err.Error(),
        })
    }

    err = utils.UpdatePassword(input.Email, input.NewPassword, c.Context())
    if err != nil {
        return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
            "error": err.Error(),
        })
    }

    return c.SendStatus(fiber.StatusNoContent)
}

API теперь создан, и тестирование можно выполнить с помощью следующей команды cURL

curl --location --request PUT 'localhost:3000/api/reset-password' \
--header 'Content-Type: application/json' \
--data-raw '{
    "email": "[email protected]",
    "new_password": "tester123",
    "otp": "DM4RDNF07B"
}'

В следующей части я начну с фронтенда

Заявление о выпуске Эта статья воспроизведена по адресу: https://dev.to/bitorsic/2-password-reset-feature-using-otp-to-reset-password-3lkj?1 Если есть какие-либо нарушения, пожалуйста, свяжитесь с [email protected] удалить его
Последний учебник Более>

Изучайте китайский

Отказ от ответственности: Все предоставленные ресурсы частично взяты из Интернета. В случае нарушения ваших авторских прав или других прав и интересов, пожалуйста, объясните подробные причины и предоставьте доказательства авторских прав или прав и интересов, а затем отправьте их по электронной почте: [email protected]. Мы сделаем это за вас как можно скорее.

Copyright© 2022 湘ICP备2022001581号-3