redis实现封禁客户端ip

有的项目客户端为了保证用户数据安全,涉及到敏感操作,会有严格的错误次数限制,比如用户多次登录失败即锁定客户端ip,防止爆破,这个用redis就可以实现(其他kv数据库也行),细节如下:

示例在eggjs下实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
async ipInspect(body) {
const { accumulate = true } = body || {}
// nginx 需设置header
let ip = this.ctx.request.get('X-Real-IP')
// 本地环境
if (this.config.env === 'local') {
ip = this.ctx.ip.includes('::1') ? '127.0.0.1' : this.ctx.ip
}
// 这里以应用名称为例
const name = this.app.config.name
// 存储此ip的计数
let key = `${name}_${ip}`
// 锁定时间
let lockSeconds = 60 * 5
// 锁定key
let lock_key = `${name}_dura_${ip}`
// 获取计数
const count = await this.app.redis.get(key)
// 获取剩余过期时间
let lock_ttl = await this.app.redis.ttl(lock_key)

// key计数大于5并且lock_key不存在时设置lock_key,保证封禁时间内lock_key有效
if (count && count >= 4 && lock_ttl < -1) {
await this.app.redis.set(lock_key, 1, 'EX', lockSeconds)
lock_ttl = lockSeconds
}
// lock_key存在时返回剩余锁定时间
if (lock_ttl >= -1) {
const remain_time = Math.ceil(lock_ttl / 60)
return remain_time
}
// accumulate为true时才累加key的值
if (accumulate) {
// 自增 1
await this.app.redis.incr(key)
// 设置过期时间,ttl 单位为秒
await this.app.redis.expire(key, 60 * 1)
}
return false
}