feature: support reset password by sms code (#365)

* add logout v2 for sso

* support sms-code login

* use db instead of memory cache for login code

* feature: support reset password by sms code
This commit is contained in:
yubo 2020-10-29 07:03:57 +08:00 committed by GitHub
parent 1fdcbd848c
commit c6b5a5b400
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 104 additions and 0 deletions

View File

@ -25,6 +25,9 @@ func Config(r *gin.Engine) {
notLogin.GET("/auth/v2/authorize", authAuthorizeV2)
notLogin.GET("/auth/v2/callback", authCallbackV2)
notLogin.GET("/auth/v2/logout", logoutV2)
notLogin.POST("/auth/send-rst-code-by-sms", sendRstCodeBySms)
notLogin.POST("/auth/rst-password", rstPassword)
}
hbs := r.Group("/api/hbs")

View File

@ -233,6 +233,7 @@ type loginInput struct {
const (
LOGIN_T_SMS = "sms-code"
LOGIN_T_EMAIL = "email-code"
LOGIN_T_RST = "rst-code"
LOGIN_T_PWD = "password"
LOGIN_T_LDAP = "ldap"
LOGIN_EXPIRES_IN = 300
@ -415,3 +416,103 @@ func emailCodeVerify(email, code string) (*models.User, error) {
return user, nil
}
type sendRstCodeBySmsInput struct {
Phone string `json:"phone"`
}
func sendRstCodeBySms(c *gin.Context) {
var f sendRstCodeBySmsInput
bind(c, &f)
msg, err := func() (string, error) {
if !config.Config.Redis.Enable {
return "", fmt.Errorf("sms sender is disabled")
}
phone := f.Phone
user, _ := models.UserGet("phone=?", phone)
if user == nil {
return "", fmt.Errorf("phone %s dose not exist", phone)
}
// general a random code and add cache
code := fmt.Sprintf("%06d", rand.Intn(1000000))
loginCode := &models.LoginCode{
Username: user.Username,
Code: code,
LoginType: LOGIN_T_RST,
CreatedAt: time.Now().Unix(),
}
if err := loginCode.Save(); err != nil {
return "", err
}
var buf bytes.Buffer
if err := loginCodeSmsTpl.Execute(&buf, loginCode); err != nil {
return "", err
}
if err := redisc.Write(&dataobj.Message{
Tos: []string{phone},
Content: buf.String(),
}, config.SMS_QUEUE_NAME); err != nil {
return "", err
}
// log.Printf("[sms -> %s] %s", phone, buf.String())
// TODO: remove code from msg
return fmt.Sprintf("[debug] msg: %s", buf.String()), nil
}()
renderData(c, msg, err)
}
type rstPasswordInput struct {
Phone string `json:"phone"`
Code string `json:"code"`
Password string `json:"password"`
}
func rstPassword(c *gin.Context) {
var in loginInput
bind(c, &in)
err := func() error {
user, _ := models.UserGet("phone=?", in.Phone)
if user == nil {
return fmt.Errorf("phone %s dose not exist", in.Phone)
}
lc, err := models.LoginCodeGet("username=? and code=? and login_type=?",
user.Username, in.Code, LOGIN_T_RST)
if err != nil {
return fmt.Errorf("invalid code", in.Phone)
}
if time.Now().Unix()-lc.CreatedAt > LOGIN_EXPIRES_IN {
return fmt.Errorf("the code has expired", in.Phone)
}
// update password
if user.Password, err = models.CryptoPass(in.Password); err != nil {
return err
}
if err = user.Update("password"); err != nil {
return err
}
lc.Del()
return nil
}()
if err != nil {
renderData(c, nil, err)
} else {
renderData(c, "reset successfully", nil)
}
}