package auth import ( "sync" "time" ) // RateLimiter 内存登录限速器:按 key(如用户名)统计连续失败次数, // 达到阈值后锁定 lockFor 时长,锁定期内 Allow 返回 false。 // 单实例内存实现即可满足(登录失败限速无跨进程一致性要求)。 type RateLimiter struct { mu sync.Mutex max int lockFor time.Duration entries map[string]*rlEntry now func() time.Time // 可注入时钟(测试) } type rlEntry struct { failures int lockedUntil time.Time } // NewRateLimiter 创建限速器。 func NewRateLimiter(max int, lockFor time.Duration) *RateLimiter { return &RateLimiter{max: max, lockFor: lockFor, entries: make(map[string]*rlEntry), now: time.Now} } // Allow 返回 key 当前是否允许继续尝试。 func (l *RateLimiter) Allow(key string) bool { l.mu.Lock() defer l.mu.Unlock() e, ok := l.entries[key] if !ok { return true } if now := l.now(); now.Before(e.lockedUntil) { return false } else if e.failures >= l.max { // 锁定已过期:重置计数,允许重试 delete(l.entries, key) return true } return true } // RecordFailure 记录一次失败;达到阈值后进入锁定。 func (l *RateLimiter) RecordFailure(key string) { l.mu.Lock() defer l.mu.Unlock() now := l.now() e, ok := l.entries[key] if !ok || now.After(e.lockedUntil) && e.failures >= l.max { e = &rlEntry{} l.entries[key] = e } e.failures++ if e.failures >= l.max { e.lockedUntil = now.Add(l.lockFor) } } // Reset 清除 key 的失败记录(登录成功后调用)。 func (l *RateLimiter) Reset(key string) { l.mu.Lock() defer l.mu.Unlock() delete(l.entries, key) }