技术无边界 | Nginx+lua+Redis实现禁止黑名单访问
我们之前有写过Nginx系列文章,知道lua是可以很好地和Nginx配合使用的,可以在进入代码之前做一些处理,我们今天不妨尝试结合Redis来实现禁止黑名单访问的demo。
这里我们力求简单,省去安装,使用OpenResty,安装我们之前曾操作过,请看这一篇文章。
我是在windows7电脑上测试使用,主要配置代码如下:
# 分配内存,根据业务量
lua_shared_dict ip_blacklist 1m;
server {
listen 80;
server_name localhost;
root E:/www/web/test;
access_log logs/host.access.log ;
error_log logs/host.error.log;
location / {
access_by_lua_file ../lua/black.lua;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
location ~ \.php$ {
# 指定lua文件
access_by_lua_file "D:\openresty-1.15.8.1-win64/lua/black.lua";
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
black.lua
local redis_port = "6379"
-- 连接超时时间,单位ms,不建议设置太高
local redis_connection_timeout = 1000
local redis_key = "ip_blacklist"
-- 缓存时间,单位s
local cache_ttl = 100
-- 以上是配置
local ip = ngx.var.remote_addr
local ip_blacklist = ngx.shared.ip_blacklist
local last_update_time = ip_blacklist:get("last_update_time");
-- 当缓存时间到期更新blacklist
if last_update_time == nil or last_update_time < ( ngx.now() - cache_ttl ) then
local redis = require "resty.redis";
local red = redis:new();
red:set_timeout(redis_connect_timeout);
local ok, err = red:connect(redis_host, redis_port);
if not ok then
ngx.say("redis connect failed: ", err)
ngx.log(ngx.DEBUG, "Redis connection error while retrieving ip_blacklist: " .. err);
return ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
else
-- local res, err = red:auth("foobared") -- 配置redis的密码,我测试未设置密码,代码注释
--if not res then
--ngx.say("redis auth is error: ", err)
--return
--end
red:select(0) -- 设置redis的db
local new_ip_blacklist, err = red:smembers(redis_key);
if err then
ngx.log(ngx.DEBUG, "Redis read error while retrieving ip_blacklist: " .. err);
else
-- 情况本地存储
ip_blacklist:flush_all();
for index, banned_ip in ipairs(new_ip_blacklist) do
ip_blacklist:set(banned_ip, true);
end
-- 更新时间
ip_blacklist:set("last_update_time", ngx.now());
end
end
end
if ip_blacklist:get(ip) then
--ngx.say(ip)
ngx.log(ngx.DEBUG, "Banned IP detected and refused access: " .. ip);
return ngx.exit(ngx.HTTP_FORBIDDEN);
end
完成。
当然了,这只是个基础版本,你可以让这个禁止访问功能更强大,比如增加可疑ip写入,比如增加ip限流等等。