Nginx + Lua(OpenResty)可在入口层实现ThinkPHP 6.0的动态IP黑名单封禁,无需侵入业务代码;需配置redis连接池、在access_by_lua_block中查询blacklist:IP并显式ngx.exit(403),配合TTL过期与后台管理接口提升实用性。

ThinkPHP 6.0 本身不内置 WAF 黑名单封禁能力,但可通过 Nginx + Lua(如 OpenResty)在请求入口层实现高效、低开销的动态黑名单控制,避免侵入业务代码,也绕过 PHP 解析开销。
一、Nginx + Lua 环境准备
需使用 OpenResty(含 Lua 和 lua-resty-redis 等常用模块),或在标准 Nginx 上编译安装 ngx_http_lua_module。确认 Lua 模块加载成功:
- 执行 nginx -V 2>&1 | grep -o with-http_lua_module,有输出即支持
- Redis 用于持久化黑名单 IP,推荐启用连接池与超时设置
- 建议将黑名单 TTL 设为 300~3600 秒,兼顾实效性与内存压力
二、Lua 脚本实现动态拦截逻辑
在 http 块中定义 Redis 连接与黑名单检查函数,例如:
lua_shared_dict ip_blacklist 10m;
init_by_lua_block {
local redis = require "resty.redis"
local red = redis:new()
red:set_timeouts(1000, 1000, 1000)
-- 可缓存连接池或延迟初始化
}
<p>access_by_lua_block {
local ip = ngx.var.remote_addr
local red = require "resty.redis":new()
red:set_timeouts(1000, 1000, 1000)
local ok, err = red:connect("127.0.0.1", 6379)
if not ok then
ngx.log(ngx.WARN, "redis connect failed: ", err)
return
end
local bl, err = red:get("blacklist:" .. ip)
if bl == "1" then
ngx.status = 403
ngx.say("Forbidden")
ngx.exit(403)
end
}注意:生产环境应复用 redis 连接池、加异常兜底、避免阻塞主流程。
立即学习“PHP免费学习笔记(深入)”;
三、ThinkPHP 6 配合触发封禁(可选)
业务侧可在登录失败、高频接口调用等场景,调用 Redis 写入黑名单:
- 使用 think-redis 扩展或原生 Redis 客户端,执行 SET blacklist:192.168.1.100 1 EX 600
- 建议封装统一方法,如 Blacklist::add($ip, $expire = 600)
- 避免直接在控制器里硬编码 Redis 操作,应通过服务类或事件监听解耦
四、增强实用性与安全性
仅封 IP 粗粒度不够,可扩展支持 User-Agent、Referer 或自定义请求头特征:
- 组合键名如 blacklist:ua:Mozilla/5.0...,配合前缀扫描清理
- 加入限流判断(如 lua-resty-limit-traffic),对同一 IP 短时高频请求自动加入黑名单
- 记录拦截日志到本地文件或 Kafka,便于审计与误封排查
- 提供后台接口(需鉴权)查询/删除黑名单项,避免全量清空风险
不复杂但容易忽略:Nginx 层封禁后,PHP 日志里将看不到被拦请求;务必同步调整日志格式与监控口径,否则会误判接口成功率。



















