package services import ( "fmt" "sync" "time" ) var ( // 登录尝试记录 loginAttempts = struct { sync.RWMutex m map[string]AttemptInfo }{m: make(map[string]AttemptInfo)} ) // AttemptInfo 登录尝试信息 type AttemptInfo struct { Count int FirstTry time.Time LockedUntil *time.Time } // CheckLoginAttempts 检查登录尝试次数 func CheckLoginAttempts(identifier string) (bool, string) { loginAttempts.RLock() info, exists := loginAttempts.m[identifier] loginAttempts.RUnlock() if !exists { return true, "" } // 检查是否被锁定 if info.LockedUntil != nil && time.Now().Before(*info.LockedUntil) { remaining := info.LockedUntil.Sub(time.Now()) return false, fmt.Sprintf("账户已锁定,请%.0f分钟后再试", remaining.Minutes()) } // 检查尝试次数 if info.Count >= 5 { // 锁定30分钟 lockedUntil := time.Now().Add(30 * time.Minute) info.LockedUntil = &lockedUntil loginAttempts.Lock() loginAttempts.m[identifier] = info loginAttempts.Unlock() return false, "尝试次数过多,账户已锁定30分钟" } return true, "" } // RecordLoginAttempt 记录登录尝试 func RecordLoginAttempt(identifier string, success bool) { loginAttempts.Lock() defer loginAttempts.Unlock() info, exists := loginAttempts.m[identifier] if success { // 登录成功,清除记录 delete(loginAttempts.m, identifier) return } if !exists { // 第一次失败 loginAttempts.m[identifier] = AttemptInfo{ Count: 1, FirstTry: time.Now(), } } else { // 增加失败次数 info.Count++ loginAttempts.m[identifier] = info // 如果30分钟内失败5次,锁定账户 if info.Count >= 5 && time.Since(info.FirstTry) <= 30*time.Minute { lockedUntil := time.Now().Add(30 * time.Minute) info.LockedUntil = &lockedUntil loginAttempts.m[identifier] = info } } // 清理30分钟前的记录 for key, attemptInfo := range loginAttempts.m { if time.Since(attemptInfo.FirstTry) > 30*time.Minute { delete(loginAttempts.m, key) } } }