利用redis配置键的过期时间做到对客户端访问频率进行判断进行限制访问,放到access_by_lua_*阶段。具体代码如下:
--Lua
--定义关闭redis函数:
local function close_redis(red)
if not red then
return
end
-- 释放连接(连接池实现),毫秒
local pool_max_idle_time = 10000
-- 连接池大小
local pool_size = 100
local ok, err = red:set_keepalive(pool_max_idle_time, pool_size)
local log = ngx_log
if not ok then
log(ngx_ERR, "set redis keepalive error : ", err)
end
end
-- 连接redis
local redis = require('resty.redis')
local red = redis.new()
red:set_timeout(1000)
local ok, err = red:connect("127.0.0.1", 6379)
if not ok then
ngx.say("failed to connect: ", err)
return
end
local res, err = red:auth("123456")
if not res then
ngx.say("failed to authenticate: ", err)
return
end
--获取客户端真实的ip:
local clientIP = ngx.req.get_headers()["X-Real-IP"]
if clientIP == nil then
clientIP = ngx.req.get_headers()["x_forwarded_for"]
end
if clientIP == nil then
clientIP = ngx.var.remote_addr
end
--定义redis key值格式,incrkey 客户端IP的请求频率键,blockKey 客户端IP禁止访问键,后面会存入redis
local incrKey = "user:"..clientIP..":freq"
local blockKey = "user:"..clientIP..":block"
-- 检查客户端IP是否被禁止访问
local is_block,err = red:get(blockKey)
if tonumber(is_block) == 1 then
ngx.exit(403)
close_redis(red)
end
--incr redis操作 默认是从0开始,执行一次会累加1
inc = red:incr(incrKey)
-- 设置键过期时间为5秒,每秒钟访问10次以上访问即视为非法,会阻止1分钟的访问
if inc < 10 then
inc = red:expire(incrKey,5)
end
if inc > 10 then
--设置block 为 True 为1
red:set(blockKey,1)
red:expire(blockKey,60)
end
close_redis(red)