Kaynağa Gözat

feat: 通过手机找回密码

runningwater 5 ay önce
ebeveyn
işleme
40e668db20

+ 1 - 0
README.md

@@ -73,6 +73,7 @@ UNIQUE KEY `migration` (`migration`)
 
 #### 🚀 新功能
 
+- 通过手机找回密码
 - *(command)* Migrate fresh
 - *(command)* Migrate reset and migrate refresh
 - *(command)* Migrate rollback 命令

+ 34 - 0
app/http/controllers/api/v1/auth/password_controller.go

@@ -0,0 +1,34 @@
+package auth
+
+import (
+	"github.com/gin-gonic/gin"
+	v1 "github.com/runningwater/gohub/app/http/controllers/api/v1"
+	"github.com/runningwater/gohub/app/models/user"
+	"github.com/runningwater/gohub/app/requests"
+	"github.com/runningwater/gohub/pkg/response"
+)
+
+type PasswordController struct {
+	v1.BaseApiController
+}
+
+func (pc *PasswordController) ResetByPhone(c *gin.Context) {
+	// 1. 验证表单
+	request := requests.ResetByPhoneRequest{}
+	if ok := requests.Validate(c, &request, requests.ResetByPhone); !ok {
+		return
+	}
+
+	// 2. 更新密码
+	userModel := user.GetByPhone(request.Phone)
+	if userModel.ID == 0 {
+		// 404
+		response.Abort404(c)
+	} else {
+		userModel.Password = request.Password
+		userModel.Save()
+
+		// 3. 成功
+		response.Success(c)
+	}
+}

+ 6 - 0
app/models/user/user_model.go

@@ -24,6 +24,12 @@ func (u *User) Create() {
 	database.DB.Create(&u)
 }
 
+// Save 保存用户信息
+func (u *User) Save() (rowsAffected int64) {
+	result := database.DB.Save(&u)
+	return result.RowsAffected
+}
+
 func (u *User) GetStringID() string {
 	return models.GetStringID(u.ID)
 }

+ 46 - 0
app/requests/password_request.go

@@ -0,0 +1,46 @@
+package requests
+
+import (
+	"github.com/gin-gonic/gin"
+	"github.com/runningwater/gohub/app/requests/validators"
+	"github.com/thedevsaddam/govalidator"
+)
+
+type ResetByPhoneRequest struct {
+	Phone      string `json:"phone,omitempty" valid:"phone"`
+	VerifyCode string `json:"verify_code,omitempty" valid:"verify_code"`
+	Password   string `json:"password,omitempty" valid:"password"`
+}
+
+// ResetByPhone 验证表单,返回长度等于零即通过
+func ResetByPhone(data any, c *gin.Context) map[string][]string {
+
+	rules := govalidator.MapData{
+		"phone":       []string{"required", "digits:11"},
+		"verify_code": []string{"required", "digits:6"},
+		"password":    []string{"required", "min:6"},
+	}
+	messages := govalidator.MapData{
+		"phone": []string{
+			"required:手机号为必填项,参数名称 phone",
+			"digits:手机号长度必须为 11 位的数字",
+		},
+		"verify_code": []string{
+			"required:验证码答案必填",
+			"digits:验证码长度必须为 6 位的数字",
+		},
+		"password": []string{
+			"required:密码为必填项",
+			"min:密码长度需大于 6",
+		},
+	}
+
+	errs := validate(data, rules, messages)
+
+	// 验证码是否正确
+	_data := data.(*ResetByPhoneRequest)
+	errs = validators.ValidateVerifyCode(_data.Phone, _data.VerifyCode, errs)
+
+	return errs
+
+}

+ 5 - 0
routes/api.go

@@ -43,6 +43,11 @@ func RegisterAPIRoutes(router *gin.Engine) {
 			authGroup.POST("/login/using-password", logc.LoginByPassword)
 			// 刷新 Access Token
 			authGroup.POST("/login/refresh-token", logc.RefreshToken)
+
+			// 重置密码
+			pc := new(auth.PasswordController)
+			// 使用手机重置密码
+			authGroup.POST("/password-reset/using-phone", middlewares.LimitPerRoute("20-H"), pc.ResetByPhone)
 		}
 	}
 }