OpenResty使用Lua大全(十)实战: Lua + Redis 实现动态封禁 IP

@[TOC]

系列文章索引

OpenResty使用Lua大全(一)Lua语法入门实战 OpenResty使用Lua大全(二)在OpenResty中使用Lua OpenResty使用Lua大全(三)OpenResty使用Json模块解析json OpenResty使用Lua大全(四)OpenResty中使用Redis OpenResty使用Lua大全(五)OpenResty中使用MySQL OpenResty使用Lua大全(六)OpenResty发送http请求 OpenResty使用Lua大全(七)OpenResty使用全局缓存 OpenResty使用Lua大全(八)OpenResty执行流程与阶段详解 OpenResty使用Lua大全(九)实战:nginx-lua-redis实现访问频率控制 OpenResty使用Lua大全(十)实战: Lua + Redis 实现动态封禁 IP OpenResty使用Lua大全(十一)实战: nginx实现接口签名安全认证 OpenResty使用Lua大全(十二)实战: 动手实现一个网关框架

一、需求背景

为了封禁某些爬虫或者恶意用户对服务器的请求,我们需要建立一个动态的 IP 黑名单。 对于黑名单之内的 IP ,拒绝提供服务。

二、设计方案

1、实现目标

实现 IP 黑名单的功能有很多途径: 1、在操作系统层面,配置 iptables,拒绝指定 IP 的网络请求; 2、在 Web Server 层面,通过 Nginx 自身的 deny 选项 或者 lua 插件 配置 IP 黑名单; 3、在应用层面,在请求服务之前检查一遍客户端 IP 是否在黑名单。

为了方便管理和共享,我们通过 Nginx+Lua+Redis 的架构实现 IP 黑名单的功能

2、nginx.conf配置

在http部分,配置本地缓存,来缓存redis中的数据,避免每次都请求redis

lua 复制代码
lua_shared_dict shared_ip_blacklist 1m; #定义ip_blacklist 本地缓存变量

location /ipblacklist {
	access_by_lua_file /usr/local/openresty/nginx/conf/access_by_limit_ip.lua;
	echo "ipblacklist";
}

3、access_by_limit_ip.lua

lua 复制代码
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)  
    if not ok then  
        ngx.say("set keepalive error : ", err)  
    end  
end

local function errlog(...)
    ngx.log(ngx.ERR, "redis: ", ...)
end

local function duglog(...)
    ngx.log(ngx.DEBUG, "redis: ", ...)
end

local function getIp()
	local myIP = ngx.req.get_headers()["X-Real-IP"]
	if myIP == nil then
		myIP = ngx.req.get_headers()["x_forwarded_for"]
	end
	if myIP == nil then
		myIP = ngx.var.remote_addr
	end
	return myIP;
end

local key = "limit:ip:blacklist"
local ip = getIp();
local shared_ip_blacklist = ngx.shared.shared_ip_blacklist

--获得本地缓存的最新刷新时间
local last_update_time = shared_ip_blacklist:get("last_update_time");

if last_update_time ~= nil then 
	local dif_time = ngx.now() - last_update_time 
	if dif_time < 60 then --缓存1分钟,没有过期
		if shared_ip_blacklist:get(ip) then
			return ngx.exit(ngx.HTTP_FORBIDDEN) --直接返回403
		end
		return
	end
end

local redis = require "resty.redis"  --引入redis模块
local red = redis:new()  --创建一个对象,注意是用冒号调用的

--设置超时(毫秒)  
red:set_timeout(1000) 
--建立连接  
local ip = "127.0.0.1"  
local port = 6379
local ok, err = red:connect(ip, port)
if not ok then  
	close_redis(red)
	errlog("limit ip cannot connect redis");
else
	local ip_blacklist, err = red:smembers(key);
	
	if err then
		errlog("limit ip smembers");
	else
		--刷新本地缓存,重新设置
		shared_ip_blacklist:flush_all();
		
		--同步redis黑名单 到 本地缓存
		for i,bip in ipairs(ip_blacklist) do
			--本地缓存redis中的黑名单
			shared_ip_blacklist:set(bip,true);
		end
		--设置本地缓存的最新更新时间
		shared_ip_blacklist:set("last_update_time",ngx.now());
	end
end  

if shared_ip_blacklist:get(ip) then
	return ngx.exit(ngx.HTTP_FORBIDDEN) --直接返回403
end

4、测试

用户redis客户端设置 sadd limit:ip:blacklist 192.168.56.1,设置黑名单访问测试。

相关推荐
Livingbody5 分钟前
通过huggingface学习【自动语音识别(Automatic Speech Recognition, ASR)】
后端
~plus~8 分钟前
Harmony核心:动态方法修补与.NET游戏Mod开发
开发语言·jvm·经验分享·后端·程序人生·c#
~plus~18 分钟前
WPF八大法则:告别模态窗口卡顿
开发语言·经验分享·后端·程序人生·c#
Livingbody23 分钟前
Transformers Pipeline 入门之【任务列表】
后端
[email protected]30 分钟前
ASP.NET Core SignalR - 部分客户端消息发送
后端·asp.net·.netcore
寻月隐君30 分钟前
深入解析 Rust 的面向对象编程:特性、实现与设计模式
后端·rust·github
追逐时光者34 分钟前
免费且全面的C#/.NET/.NET Core面试宝典,阅读量突破40万+了!
后端·.net
编程乐学(Arfan开发工程师)1 小时前
42、响应处理-【源码分析】-浏览器与PostMan内容协商完全适配
java·spring boot·后端·测试工具·lua·postman
汪子熙1 小时前
深入解析互斥锁(Mutex):并发编程中的关键同步机制
后端·面试
Livingbody1 小时前
mac系统下永久设置环境变量之【huggingface更换镜像站】
后端