Weiter zur nächsten API.
PUT auf /api/reset-password, req -> otp, email, neues Passwort, 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) }
Route dafür wird hinzugefügt
// routes/routes.go api.Put("/reset-password", controllers.ResetPassword)
Jetzt brauche ich zwei Funktionen:
// 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 }
Jetzt muss ich beide im Controller zusammenfügen. Ich verwende die Funktion bool from VerifyOTP, um anzugeben, ob es sich bei dem Fehler um einen internen Fehler handelt oder ob er an der Eingabe liegt.
// 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) }
Die API ist jetzt erstellt und der Test kann mit dem folgenden cURL-Befehl durchgeführt werden
curl --location --request PUT 'localhost:3000/api/reset-password' \ --header 'Content-Type: application/json' \ --data-raw '{ "email": "[email protected]", "new_password": "tester123", "otp": "DM4RDNF07B" }'
Im nächsten Teil beginne ich mit dem Frontend
Haftungsausschluss: Alle bereitgestellten Ressourcen stammen teilweise aus dem Internet. Wenn eine Verletzung Ihres Urheberrechts oder anderer Rechte und Interessen vorliegt, erläutern Sie bitte die detaillierten Gründe und legen Sie einen Nachweis des Urheberrechts oder Ihrer Rechte und Interessen vor und senden Sie ihn dann an die E-Mail-Adresse: [email protected] Wir werden die Angelegenheit so schnell wie möglich für Sie erledigen.
Copyright© 2022 湘ICP备2022001581号-3