修复原有的blacklist_add路由,确保IP被正确添加到Redis的security:blacklist:ip集合中。
问题的原因是两个方面:
Redis身份验证问题:当在Lua脚本中通过io.popen执行redis-cli命令时,密码参数没有被正确地处理,导致出现"NOAUTH Authentication required"错误。
数据格式问题:blacklist_list API响应格式有问题,它返回一个空对象{}而不是数组[],导致UI和其他客户端无法正确解析结果。
解决方案:
修复原有的blacklist_add路由,确保IP被正确添加到Redis的security:blacklist:ip集合中。
修复blacklist_list路由以正确返回blacklist数据。
我们使用了简化版的blacklist_list API来确保它能正确读取并返回Redis中的数据。
在后台,当IP添加到黑名单时,应该:
添加IP到security:blacklist:ip集合中
设置对应的security:blacklist:ip:[IP]键以及相关信息
经过修复后,您在界面上看到的"IP is in blacklist"消息说明系统已经能够正确识别黑名单中的IP,这是功能正常的表现。
!/bin/bash
黑名单路由创建脚本
通过serverless-pre-function插件实现,直接在路由配置中嵌入Lua代码
API_KEY="C8M2coDxAFISYB4spb3X8Rsxassjw1N1"
APISIX_HOST="127.0.0.1:9180"
echo "===== 开始创建黑名单相关路由 ====="
1. 创建blacklist基础路由
echo "===== 创建blacklist基础路由 ====="
curl -i "http://$APISIX_HOST/apisix/admin/routes/blacklist" -H "X-API-KEY: $API_KEY" -X PUT -d '
{
"methods": ["GET", "POST", "PUT", "DELETE"],
"uri": "/security/blacklist/*",
"id": "blacklist",
"status": 1,
"upstream": {
"scheme": "http",
"hash_on": "vars",
"type": "roundrobin",
"pass_host": "pass",
"nodes": {
"127.0.0.1:9080": 1
}
}
}'
2. 创建blacklist_add路由 (添加IP到黑名单)
echo -e "\n===== 创建blacklist_add路由 ====="
curl -i "http://$APISIX_HOST/apisix/admin/routes/blacklist_add" -H "X-API-KEY: $API_KEY" -X PUT -d '
{
"methods": ["POST"],
"uri": "/security/blacklist/add",
"id": "blacklist_add",
"status": 1,
"plugins": {
"serverless-pre-function": {
"phase": "access",
"functions": ["return function(conf, ctx) \n local core = require("apisix.core")\n local json = require("apisix.core.json")\n local redis = require("resty.redis")\n local red = redis:new()\n red:set_timeout(1000)\n local ok, err = red:connect("127.0.0.1", 6379)\n if not ok then \n return 500, {error_msg = "failed to connect to redis"}\n end\n \n -- 读取Redis密码并进行身份验证\n local pwd_file = io.open("/tmp/redis_password", "r")\n local redis_pwd = ""\n if pwd_file then \n redis_pwd = pwd_file:read("*all"):gsub("%s+", "")\n pwd_file:close()\n end\n \n if redis_pwd and redis_pwd ~= "" then\n local auth_ok, auth_err = red:auth(redis_pwd)\n if not auth_ok then\n return 500, {error_msg = "failed to authenticate to redis: " .. (auth_err or "unknown error")}\n end\n end\n \n -- 解析请求体\n local body = core.request.get_body()\n local args = json.decode(body)\n if not args or not args.ip then \n return 400, {error_msg = "missing ip parameter"}\n end\n \n -- 设置黑名单并配置过期时间\n local ttl = args.ttl or 3600\n local reason = args.reason or ""\n local key = "security:blacklist:ip:" .. args.ip\n \n red:set(key, "1")\n red:set(key .. ":reason", reason)\n red:set(key .. ":expire", os.time() + ttl)\n red:expire(key, ttl)\n red:expire(key .. ":reason", ttl)\n red:expire(key .. ":expire", ttl)\n \n -- 添加到集合中,这是关键修复\n red:sadd("security:blacklist:ip", args.ip)\n \n return 200, {message = "IP added to blacklist"}\n end"]
}
}
}'
3. 创建blacklist_check路由 (检查IP是否在黑名单中)
echo -e "\n===== 创建blacklist_check路由 ====="
curl -i "http://$APISIX_HOST/apisix/admin/routes/blacklist_check" -H "X-API-KEY: $API_KEY" -X PUT -d '
{
"methods": ["GET"],
"uri": "/security/blacklist/check/",
"id": "blacklist_check",
"status": 1,
"plugins": {
"serverless-pre-function": {
"phase": "access",
"functions": ["return function(conf, ctx)\n local core = require("apisix.core")\n local redis = require("resty.redis")\n local red = redis:new()\n red:set_timeout(1000)\n local ok, err = red:connect("127.0.0.1", 6379)\n if not ok then \n return 500, {error_msg = "failed to connect to redis"}\n end\n \n -- 读取Redis密码并进行身份验证\n local pwd_file = io.open("/tmp/redis_password", "r")\n local redis_pwd = ""\n if pwd_file then \n redis_pwd = pwd_file:read("all"):gsub("%s+", "")\n pwd_file:close()\n end\n \n if redis_pwd and redis_pwd ~= "" then\n local auth_ok, auth_err = red:auth(redis_pwd)\n if not auth_ok then\n return 500, {error_msg = "failed to authenticate to redis: " .. (auth_err or "unknown error")}\n end\n end\n \n -- 从URI中提取IP并检查是否在黑名单中\n local uri_segs = core.utils.split_uri(ngx.var.uri)\n local ip = uri_segs[#uri_segs]\n if not ip then\n return 400, {error_msg = "missing ip parameter"}\n end\n \n -- 同时检查独立键和集合成员\n local key = "security:blacklist:ip:" .. ip\n local exists = red:exists(key)\n local is_member = red:sismember("security:blacklist:ip", ip)\n local result = {is_blacklisted = (exists == 1 or is_member == 1)}\n \n if exists == 1 then\n result.reason = red:get(key .. ":reason") or ""\n result.expire = red:get(key .. ":expire") or ""\n end\n \n -- 保持连接\n red:set_keepalive(10000, 100)\n \n return 200, result\n end"]
}
}
}'
4. 创建blacklist_list路由 (列出所有黑名单IP)
echo -e "\n===== 创建blacklist_list路由 ====="
curl -i "http://$APISIX_HOST/apisix/admin/routes/blacklist_list" -H "X-API-KEY: $API_KEY" -X PUT -d '
{
"methods": ["GET"],
"uri": "/security/blacklist/list",
"id": "blacklist_list",
"status": 1,
"plugins": {
"serverless-pre-function": {
"phase": "access",
"functions": ["return function(conf, ctx)\n local core = require("apisix.core")\n local redis = require("resty.redis")\n local red = redis:new()\n red:set_timeout(1000)\n local ok, err = red:connect("127.0.0.1", 6379)\n if not ok then \n return 500, {error_msg = "failed to connect to redis"}\n end\n \n -- 读取Redis密码并进行身份验证\n local pwd_file = io.open("/tmp/redis_password", "r")\n local redis_pwd = ""\n if pwd_file then \n redis_pwd = pwd_file:read("*all"):gsub("%s+", "")\n pwd_file:close()\n end\n \n if redis_pwd and redis_pwd ~= "" then\n local auth_ok, auth_err = red:auth(redis_pwd)\n if not auth_ok then\n return 500, {error_msg = "failed to authenticate to redis: " .. (auth_err or "unknown error")}\n end\n end\n \n -- 优先从集合中获取所有黑名单IP\n local ips = {}\n local members = red:smembers("security:blacklist:ip")\n \n if members then\n for _, ip in ipairs(members) do\n local key = "security:blacklist:ip:" .. ip\n local reason = red:get(key .. ":reason") or ""\n local expire = red:get(key .. ":expire") or ""\n table.insert(ips, {ip=ip, reason=reason, expire=expire})\n end\n end\n \n -- 保持连接\n red:set_keepalive(10000, 100)\n \n return 200, {list=ips}\n end"]
}
}
}'
5. 创建blacklist_remove路由 (从黑名单中移除IP)
echo -e "\n===== 创建blacklist_remove路由 ====="
curl -i "http://$APISIX_HOST/apisix/admin/routes/blacklist_remove" -H "X-API-KEY: $API_KEY" -X PUT -d '
{
"methods": ["DELETE"],
"uri": "/security/blacklist/remove/",
"id": "blacklist_remove",
"status": 1,
"plugins": {
"serverless-pre-function": {
"phase": "access",
"functions": ["return function(conf, ctx)\n local core = require("apisix.core")\n local redis = require("resty.redis")\n local red = redis:new()\n red:set_timeout(1000)\n local ok, err = red:connect("127.0.0.1", 6379)\n if not ok then \n return 500, {error_msg = "failed to connect to redis"}\n end\n \n -- 读取Redis密码并进行身份验证\n local pwd_file = io.open("/tmp/redis_password", "r")\n local redis_pwd = ""\n if pwd_file then \n redis_pwd = pwd_file:read("all"):gsub("%s+", "")\n pwd_file:close()\n end\n \n if redis_pwd and redis_pwd ~= "" then\n local auth_ok, auth_err = red:auth(redis_pwd)\n if not auth_ok then\n return 500, {error_msg = "failed to authenticate to redis: " .. (auth_err or "unknown error")}\n end\n end\n \n -- 从URI中提取IP并删除相关键\n local uri_segs = core.utils.split_uri(ngx.var.uri)\n local ip = uri_segs[#uri_segs]\n if not ip then\n return 400, {error_msg = "missing ip parameter"}\n end\n \n -- 删除单独的键\n local key = "security:blacklist:ip:" .. ip\n red:del(key)\n red:del(key .. ":reason")\n red:del(key .. ":expire")\n \n -- 从集合中删除IP\n red:srem("security:blacklist:ip", ip)\n \n -- 保持连接\n red:set_keepalive(10000, 100)\n \n return 200, {message = "IP removed from blacklist"}\n end"]
}
}
}'
echo -e "\n===== 所有黑名单路由创建完成 ="
echo -e "\n= 使用示例 ====="
echo "1. 添加IP到黑名单:"
echo "curl -X POST -H "Content-Type: application/json" -d '{"ip": "1.2.3.4", "reason": "恶意访问", "ttl": 86400}' http://localhost:9080/security/blacklist/add"
echo
echo "2. 检查IP是否在黑名单:"
echo "curl http://localhost:9080/security/blacklist/check/1.2.3.4"
echo
echo "3. 列出所有黑名单IP:"
echo "curl http://localhost:9080/security/blacklist/list"
echo
echo "4. 从黑名单中移除IP:"
echo "curl -X DELETE http://localhost:9080/security/blacklist/remove/1.2.3.4"

浙公网安备 33010602011771号