}
Access_by_redis.lua
参考了下v2ex.com的做法,redis存储方案只做简单地string存储就足够了。key分别是:
用户登录记录:user:127.0.0.1:time(unix时间戳)
访问限制:block:127.0.0.1
先连接Redis吧:
local red = redis:new()
function M:redis()
red:set_timeout(1000)
local ok, err = red:connect("127.0.0.1", 6379)
if not ok then
ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
end
end
按照我们的逻辑方案,第二步是,检测是否forbidden,下面我们就检测block:127.0.0.1,如果搜索到数据,检测时间是否过期,未过期返回403,否则直接返回200:
function M:check1() local time=os.time()--system time
local res, err = red:get("block:"..ngx.var.remote_addr)
if not res then-- redis error
ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) --redis get data error end
if type(res) == "string" then --if red not null then type(red)==string
if tonumber(res) >= tonumber(time) then --check if forbidden expired
ngx.exit(ngx.HTTP_FORBIDDEN)
--ngx.say("forbidden")
end
end
}
接下来会做检测,是否访问频率过高,如果过高,要拉到黑名单的,
实现的方法是,检测user:127.0.0.1:time的值是否超标:
function M:check2() local time=os.time()--system time
local res, err = red:get("user:"..ngx.var.remote_addr..":"..time)
if not res then-- redis error
ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) --redis get data error
end
if type(res) == "string" then
if tonumber(res) >= 10 then -- attack, 10 times request/s
red:del("block:"..self.ip)
red:set("block:"..self.ip, tonumber(time)+5*60 ) --set block time
ngx.exit(ngx.HTTP_FORBIDDEN)
end
end
end
最后呢,还要记得,把每次访问时间做一个自增长,user:127.0.0.1:time:
function M:add() local time=os.time()--system time
ok, err = red:incr("user:"..ngx.var.remote_addr..":"..time)
if not ok then
ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) --redis get data error
end
end
那么,测试,强刷几次浏览器,发现过一会,返回了403,ok,搞定。
本文原创地址:http://www.iyunv.com/lua-access-control-redis.html