文档: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 = selfconf.host = host or conf.hostconf.pwd = pwd or conf.pwdconf.port = port or conf.portreturn oend-- 连接Redisfunction BlackList:connect()-- 设置连接超时时间 1sred:set_timeout(1000)local ok, err = red:connect(conf.host, conf.port)if not ok thenself:close()returnendif conf.pwd ~= "" and conf.pwd ~= nil then-- 验证redis密码local res, err = red:auth(conf.pwd)if not res thenself:close()returnendendreturnend-- 关闭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()endend-- 从redis中获取ip黑名单列表function BlackList:getList()-- 连接redisself:connect()local resp, err = red:smembers("blacklist")if not resp thenself:close()returnend-- 得到的数据为空处理if resp == ngx.null thenresp = nilend-- 随手关闭redis连接,好习惯,反正在这里关闭连接,也只是将连接回归连接池,下次连接也不需要重新握手self:close()return respend-- 刷新黑名单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 thenreturnend-- 将共享内存中的数据清除blacklist:flush_all()-- 循环插入新的黑名单列表到共享内存中for key, ip in ipairs(new_blacklist) doblacklist:set(ip, true)end-- 更新:共享内存中的更新时间blacklist:set("last_update_time", current_time)endend-- 校验IP是否存在黑名单中function BlackList:checkIp(ip)if blacklist:get(ip) thenreturn trueendreturn falseend-- 将类返回return BlackList
在另一个文件中调用该黑名单服务类:test.lua
local BlackList = require "BlackList"local bl = BlackList:new()-- 先调用刷新bl:reflush_blacklist()-- 然后判断当前IP是否存在黑名单列表中local ip = ngx.var.remote_addrlocal 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
