Passando para a próxima API.
COLOQUE em /api/reset-password, req -> otp, email, nova senha, 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) }
Adicionando rota para ele
// routes/routes.go api.Put("/reset-password", controllers.ResetPassword)
Agora preciso de duas funções:
// 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 }
Agora preciso colocar os dois juntos no controlador. Estou usando o bool da função VerifyOTP para indicar se o erro é um erro interno ou é por causa da entrada.
// 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) }
A API agora está construída e o teste pode ser feito usando o seguinte comando 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" }'
Na próxima parte, começarei com o frontend
Isenção de responsabilidade: Todos os recursos fornecidos são parcialmente provenientes da Internet. Se houver qualquer violação de seus direitos autorais ou outros direitos e interesses, explique os motivos detalhados e forneça prova de direitos autorais ou direitos e interesses e envie-a para o e-mail: [email protected]. Nós cuidaremos disso para você o mais rápido possível.
Copyright© 2022 湘ICP备2022001581号-3