在登录功能中,如果不加限制,攻击者可能会通过 暴力破解 尝试大量密码组合,带来安全风险。
一个常见解决方案是:在一定时间内限制用户的登录尝试次数,超过次数就锁定一段时间。
Redis 的高性能和天然的过期机制,非常适合实现这种登录限流功能。本文将通过 Go + Redis 实现一个 用户登录次数限制 示例。
一、场景说明
- • 规则:每个用户 1 分钟内最多尝试登录 5 次
- • 超过限制:锁定 1 分钟,不允许继续登录
- • 实现方式:
-
- • 登录时,在 Redis 中维护一个计数器
- • 如果计数器超过阈值,就禁止登录
二、环境准备
安装依赖:
go
go get github.com/redis/go-redis/v9
确保本地或 Docker 中已运行 Redis:
arduino
docker run -d -p 6379:6379 redis
三、Redis 工具初始化
go
package main
import (
"context"
"fmt"
"github.com/redis/go-redis/v9"
"log"
"time"
)
var ctx = context.Background()
var rdb *redis.Client
func initRedis() {
rdb = redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "",
DB: 0,
})
if _, err := rdb.Ping(ctx).Result(); err != nil {
log.Fatal("Redis 连接失败:", err)
}
log.Println("Redis 连接成功")
}
四、实现登录次数限制
go
// CheckLoginLimit 检查用户是否超过登录限制
func CheckLoginLimit(username string) bool {
key := fmt.Sprintf("login:%s", username)
limit := 5 // 最大尝试次数
blockTime := time.Minute // 超过限制后锁定时间
// 自增计数器
count, err := rdb.Incr(ctx, key).Result()
if err != nil {
log.Println("Redis 错误:", err)
return false
}
if count == 1 {
// 第一次设置过期时间
rdb.Expire(ctx, key, blockTime)
}
if count > int64(limit) {
return false // 超过限制
}
return true
}
五、模拟用户登录逻辑
c
// MockLogin 模拟登录
func MockLogin(username, password string) {
if !CheckLoginLimit(username) {
log.Printf("用户 %s 登录失败: 尝试次数过多,请稍后再试\n", username)
return
}
// 假设正确密码是 "123456"
if password == "123456" {
log.Printf("用户 %s 登录成功\n", username)
// 成功后清除计数器
rdb.Del(ctx, fmt.Sprintf("login:%s", username))
} else {
log.Printf("用户 %s 登录失败: 密码错误\n", username)
}
}
六、测试效果
less
func main() {
initRedis()
for i := 1; i <= 7; i++ {
MockLogin("alice", "wrongpass")
}
}
运行结果:
用户 alice 登录失败: 密码错误
用户 alice 登录失败: 密码错误
用户 alice 登录失败: 密码错误
用户 alice 登录失败: 密码错误
用户 alice 登录失败: 密码错误
用户 alice 登录失败: 尝试次数过多,请稍后再试
用户 alice 登录失败: 尝试次数过多,请稍后再试
七、总结
通过本案例,我们实现了:
- • 使用 Redis 存储用户登录尝试次数
- • 借助
INCR+EXPIRE实现自动计数和过期清理 - • 登录成功时清除计数器,避免误封
✅ 应用场景:
- • 登录安全限制(防止暴力破解)
- • API 请求限流
- • 手机验证码发送频率控制