文档:https://github.com/openresty/lua-resty-redis Lua学习:https://www.yuque.com/oyyh/lua
安装lua-resty-redis模块
- 将模块从github下载到本地
wget https://github.com/openresty/lua-resty-redis/archive/refs/tags/v0.29.tar.gz
tar -zxvf v0.29.tar.gz
cd lua-resty-redis-0.29
pwd
- 修改nginx.conf配置文件,将上面的路径添加到lua_package_path
lua_package_path “/home/data/lua-resty-redis-0.29;;”;
- 重启nginx
/usr/local/nginx/nginx -s reload
Nginx配置
http {
...
# 设置一块共享内存空间,可以被各个worker进程
lua_shared_dict blacklist 5m;
location /lua {
# lua_code_cache off;
access_by_lua_file /home/data/lua_code/test.lua;
default_type 'text/html';
content_by_lua 'ngx.say("hello world")';
}
}
黑名单服务类
下述这个BlackList.lua文件放置的目录,记得配置到nginx.conf中的lua_package_path属性中。
例如:
# 文件位置
/home/data/lua_code/BlackList.lua
# 那么在nginx.conf中,我应该这么配:
lua_package_path “/home/data/lua-resty-redis-0.29;/home/data/lua_code/?.lua;;”;
如果不按照上面这么配置,那么在其他地方require该文件的时候,会找不到这个模块
local redis = require "resty.redis"
local red = redis:new() -- 实例化Redis对象
-- 获取nginx中配置的共享内存的dict对象
local blacklist = ngx.shared.blacklist
-- Redis相关配置
local conf = {
host = "127.0.0.1",
port = 6379,
pwd = "",
}
-- 定义黑名单服务类
local BlackList = {}
-- 初始化对象
function BlackList:new(host, pwd, port)
o = {}
setmetatable(o, self)
self.__index = self
conf.host = host or conf.host
conf.pwd = pwd or conf.pwd
conf.port = port or conf.port
return o
end
-- 连接Redis
function BlackList:connect()
-- 设置连接超时时间 1s
red:set_timeout(1000)
local ok, err = red:connect(conf.host, conf.port)
if not ok then
self:close()
return
end
if conf.pwd ~= "" and conf.pwd ~= nil then
-- 验证redis密码
local res, err = red:auth(conf.pwd)
if not res then
self:close()
return
end
end
return
end
-- 关闭Redis连接
function BlackList:close()
-- 将连接归还连接池,并配置连接池大小
local time = 10000 -- 指定连接在连接池中最大空闲时间,单位毫秒(ms)
local size = 100 -- 连接池大小
local ok, err = red:set_keepalive(time, size)
if not ok then
-- 放入连接池失败,直接关闭连接
redis:close()
end
end
-- 从redis中获取ip黑名单列表
function BlackList:getList()
-- 连接redis
self:connect()
local resp, err = red:smembers("blacklist")
if not resp then
self:close()
return
end
-- 得到的数据为空处理
if resp == ngx.null then
resp = nil
end
-- 随手关闭redis连接,好习惯,反正在这里关闭连接,也只是将连接回归连接池,下次连接也不需要重新握手
self:close()
return resp
end
-- 刷新黑名单
function BlackList:reflush_blacklist()
-- 获取当前时间
local current_time = ngx.now()
-- 获取nginx共享内存块的更新时间
local last_update_time = blacklist:get("last_update_time")
-- 判断共享内存的更新时间是否超过1分钟,如果超过一分钟则更新共享内存的数据为redis中的最新数据
if last_update_time == nil or last_update_time < (current_time - 60) then
-- 从redis中获取最新的黑名单列表
local new_blacklist = self:getList()
if not new_blacklist then
return
end
-- 将共享内存中的数据清除
blacklist:flush_all()
-- 循环插入新的黑名单列表到共享内存中
for key, ip in ipairs(new_blacklist) do
blacklist:set(ip, true)
end
-- 更新:共享内存中的更新时间
blacklist:set("last_update_time", current_time)
end
end
-- 校验IP是否存在黑名单中
function BlackList:checkIp(ip)
if blacklist:get(ip) then
return true
end
return false
end
-- 将类返回
return BlackList
在另一个文件中调用该黑名单服务类:test.lua
local BlackList = require "BlackList"
local bl = BlackList:new()
-- 先调用刷新
bl:reflush_blacklist()
-- 然后判断当前IP是否存在黑名单列表中
local ip = ngx.var.remote_addr
local inList = bl:checkIp(ip)
if inList then
-- 将请求终止,并返回403状态码
return ngx.exit(ngx.HTTP_FORBIDDEN)
end
在Redis中添加黑名单
添加黑名单
SADD blacklist "127.0.0.1"
移除黑名单
SREM blacklist "127.0.0.1"
访问测试
curl http://localhost/lua