diff --git a/lib/dborm/dborm.go b/lib/dborm/dborm.go index 3567d1af..dcf3fd95 100644 --- a/lib/dborm/dborm.go +++ b/lib/dborm/dborm.go @@ -677,12 +677,87 @@ type User struct { Status string `json:"status"` UserExpiration string `json:"userExpiration"` GroupName string `json:"groupId" xorm:"group_name"` - Profile string `json:"profile" xorm:"-"` + Profile string `json:"profile" xorm:"profile"` Phone string `json:"phone" xorm:"phone"` CreateTime string `json:"createTime" xorm:"create_time"` UpdateTime string `json:"updateTime" xorm:"update_time"` } +// 记录密码登录错误次数 +func pwdErrCountAdd(accountId, profileStr string, reset bool) int { + if profileStr == "" { + profileStr = "{}" + } + profile := make(map[string]any) + count := 0 + timeMlli := time.Now().UnixMilli() + + // 反序列去值 + err := json.Unmarshal([]byte(profileStr), &profile) + if err != nil { + log.Error("json Unmarshal:%s", err.Error()) + return 0 + } + + // 重置 + if reset { + xEngine.Exec("UPDATE user SET status = 'Active' WHERE account_id = ?", accountId) + profile["pwdErrCount"] = float64(0) + profile["pwdErrTime"] = 0 + } else { + if v, ok := profile["pwdErrTime"]; ok && v != nil { + // 获取当前时间 + currentTime := time.Now() + + // 获取给定的时间戳(毫秒) + timestamp := int64(v.(float64)) // 要比较的时间戳(毫秒) + // 将时间戳转换为时间类型 + tm := time.Unix(timestamp/1000, (timestamp%1000)*int64(time.Millisecond)) + + // 计算当前时间与给定时间之间的差值 + duration := currentTime.Sub(tm) + + // 比较差值是否超过30分钟 + if duration.Minutes() > 30 { + xEngine.Exec("UPDATE user SET status = 'Active' WHERE account_id = ?", accountId) + profile["pwdErrCount"] = float64(0) + profile["pwdErrTime"] = 0 + } + } + + if v, ok := profile["pwdErrCount"]; ok && v != nil { + count = int(v.(float64)) + 1 + profile["pwdErrCount"] = count + profile["pwdErrTime"] = timeMlli + // 错误最大后锁定 + if count == 3 { + _, err := xEngine.Exec("UPDATE user SET status = 'Locked' WHERE account_id = ?", accountId) + if err != nil { + return count + } + } else if count > 3 { + return count + } + } else { + count = 1 + profile["pwdErrCount"] = count + profile["pwdErrTime"] = timeMlli + } + } + + // 序列后记录 + strByte, err := json.Marshal(profile) + if err != nil { + log.Error("json Marshal:%s", err.Error()) + return count + } + _, err = xEngine.Exec("UPDATE user SET profile = ? WHERE account_id = ?", string(strByte), accountId) + if err != nil { + return count + } + return count +} + func XormCheckLoginUser(name, password, cryptArgo string) (bool, *User, error) { log.Info("XormCheckLoginUser processing... ") @@ -710,9 +785,18 @@ func XormCheckLoginUser(name, password, cryptArgo string) (bool, *User, error) { return false, nil, err } if oauth.BcryptCompare(user.Password, password) != nil { - err := errors.New("Incorrect login name or password") + err := errors.New("用户名或密码错误") log.Error(err) + // 记录错误 + errCoutn := pwdErrCountAdd(user.AccountId, user.Profile, false) + if errCoutn > 3 { + return false, nil, errors.New("登录失败次数过多,请30分钟后重试") + } return false, nil, err + } else if user.Status != "Closed" && user.Status != "Locked" { + // 重置错误次数 + pwdErrCountAdd(user.AccountId, user.Profile, true) + user.Status = "Active" } default: err := errors.New("Incorrect crypt algoritmo")