@http://127.0.0.1:9180/apisix/admin/plugin_metadata/ip-blacklist 这是一种什么方式 获取 黑名单
这是 APISIX 官方标准的 "Plugin Metadata" 机制,是章亦春设计的一种优雅方式,用于存储和管理插件的全局配置。
在 APISIX 中,/apisix/admin/plugin_metadata/{plugin-name} 接口允许你:
存储特定插件的全局配置数据
这些数据会被所有使用该插件的路由共享
避免在每个路由上重复配置
对于黑名单管理,这种方式比创建自定义资源类型更符合 APISIX 的设计理念,因为:
它使用现有的机制,不需要增加新的资源类型
数据存储在 etcd 中,保持了高可用性
这是章亦春的设计风格的体现 - 尽可能复用现有机制解决问题,而不是创建新的实现。所有通过此API更新的黑名单配置会立即对整个系统生效。
APISIX IP黑名单插件实现指南
本文档介绍如何使用Apache APISIX的Plugin Metadata机制实现IP黑名单功能。
Plugin Metadata机制简介
Plugin Metadata是APISIX中用于存储插件全局配置的机制,由章亦春设计。它允许:
- 为特定插件定义全局配置,所有使用该插件的路由共享这些配置
- 配置存储在etcd中,确保高可用性和集群一致性
- 支持动态更新,无需重启APISIX
访问方式:
GET/PUT/DELETE http://127.0.0.1:9180/apisix/admin/plugin_metadata/{plugin-name}
IP黑名单插件实现
1. 插件定义
插件文件:/usr/local/apisix/apisix/plugins/ip-blacklist.lua
-- IP黑名单插件
-- 基于Redis的高性能IP黑名单/白名单管理
local redis = require("resty.redis")
local core = require("apisix.core")
local plugin_name = "ip-blacklist"
local schema = {
type = "object",
properties = {
redis_host = {type = "string", default = "127.0.0.1"},
redis_port = {type = "integer", default = 6379},
redis_password = {type = "string"},
redis_database = {type = "integer", default = 0},
redis_timeout = {type = "integer", default = 1000},
blacklist_key = {type = "string", default = "ip_blacklist"},
whitelist_key = {type = "string", default = "ip_whitelist"},
rejected_code = {type = "integer", default = 403},
},
required = {"redis_host", "redis_port"}
}
-- 插件元数据配置
local metadata_schema = {
type = "object",
properties = {
redis_host = {type = "string", default = "127.0.0.1"},
redis_port = {type = "integer", default = 6379},
redis_password = {type = "string"},
redis_database = {type = "integer", default = 0},
blacklist_key = {type = "string", default = "ip_blacklist"},
whitelist_key = {type = "string", default = "ip_whitelist"},
blacklist = {type = "array"} -- 黑名单IP列表
}
}
local _M = {
version = 0.1,
priority = 2900,
name = plugin_name,
schema = schema,
metadata_schema = metadata_schema
}
-- 插件逻辑实现...
-- 检查IP是否在黑名单
function _M.rewrite(conf, ctx)
local ip = core.request.get_remote_ip(ctx)
if not ip then
return 500, {message = "无法获取客户端IP"}
end
-- 获取插件元数据
local meta_data = core.plugin.plugin_metadata(plugin_name)
if meta_data and meta_data.value and meta_data.value.blacklist then
for _, item in ipairs(meta_data.value.blacklist) do
-- 支持两种格式: 简单字符串或对象结构
local blocked_ip = nil
local expire_time = nil
if type(item) == "string" then
blocked_ip = item
elseif type(item) == "table" and item.ip then
blocked_ip = item.ip
-- 检查过期时间
if item.expire and item.start_time then
local current_time = os.time()
local end_time = item.start_time + item.expire
if current_time > end_time then
-- 已过期,跳过此IP
goto continue
end
expire_time = end_time
end
end
-- 检查IP是否匹配
if blocked_ip == ip then
local msg = "IP在黑名单中"
if expire_time then
msg = msg .. ",将在 " .. os.date("%Y-%m-%d %H:%M:%S", expire_time) .. " 解除屏蔽"
end
return conf.rejected_code, {message = msg}
end
::continue::
end
end
end
return _M
2. 配置插件
在config.yaml中启用插件
文件:/usr/local/apisix/conf/config.yaml
plugins:
- ip-blacklist
deployment:
admin:
admin_key_required: true
admin_key:
-
name: admin
key: edd1c9f034335f136f87ad84b625c8f1
role: admin
设置Plugin Metadata
设置Redis连接和黑名单:
curl http://127.0.0.1:9180/apisix/admin/plugin_metadata/ip-blacklist -H "X-API-KEY: edd1c9f034335f136f87ad84b625c8f1" -X PUT -d '{
"redis_host": "127.0.0.1",
"redis_port": 6379,
"redis_database": 0,
"blacklist_key": "ip_blacklist",
"whitelist_key": "ip_whitelist",
"blacklist": [
{"ip": "192.168.1.100", "expire": 3600, "start_time": 1747870000},
{"ip": "192.168.1.101", "expire": 7200, "start_time": 1747870000}
]
}'
创建使用插件的路由
curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: edd1c9f034335f136f87ad84b625c8f1" -X PUT -d '{
"uri": "/*",
"plugins": {
"ip-blacklist": {
"rejected_code": 403
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:9080": 1
}
}
}'
3. 重新加载APISIX
apisix reload
黑名单管理API
查看黑名单配置
curl http://127.0.0.1:9180/apisix/admin/plugin_metadata/ip-blacklist -H "X-API-KEY: edd1c9f034335f136f87ad84b625c8f1"
更新黑名单
添加新的IP到黑名单:
# 先获取当前配置
META_DATA=$(curl -s http://127.0.0.1:9180/apisix/admin/plugin_metadata/ip-blacklist -H "X-API-KEY: edd1c9f034335f136f87ad84b625c8f1")
# 提取现有黑名单并添加新IP
BLACKLIST=$(echo $META_DATA | grep -o '"blacklist":\[[^]]*\]' | sed 's/"blacklist"://')
NEW_BLACKLIST=$(echo $BLACKLIST | sed 's/\]/, {"ip": "10.0.0.1", "expire": 86400, "start_time": '$(date +%s)'}\]/')
# 构建新的配置
NEW_META=$(echo $META_DATA | sed "s/\"blacklist\":\[[^]]*\]/\"blacklist\":$NEW_BLACKLIST/")
# 更新配置
curl http://127.0.0.1:9180/apisix/admin/plugin_metadata/ip-blacklist -H "X-API-KEY: edd1c9f034335f136f87ad84b625c8f1" -X PUT -d "$NEW_META"
删除IP从黑名单
类似添加,但操作是从数组中移除指定IP的项。
优点与特性
- 高效: 黑名单检查在Lua层完成,性能好
- 灵活: 支持带过期时间的IP黑名单
- 动态: 可随时更新黑名单而无需重启服务
- 集成: 完全使用APISIX现有API机制
- 符合章亦春风格: 简洁、高效、优雅
自动化脚本示例
添加IP到黑名单的脚本add_to_blacklist.sh:
#!/bin/bash
# 参数检查
if [ -z "$1" ]; then
echo "用法: $0 <IP地址> [过期时间(秒)]"
exit 1
fi
IP=$1
EXPIRE=${2:-3600} # 默认1小时
NOW=$(date +%s)
# 获取当前元数据
META_DATA=$(curl -s http://127.0.0.1:9180/apisix/admin/plugin_metadata/ip-blacklist -H "X-API-KEY: edd1c9f034335f136f87ad84b625c8f1")
# 检查是否有现有黑名单
if echo "$META_DATA" | grep -q '"blacklist":'; then
# 提取现有黑名单
BLACKLIST=$(echo $META_DATA | grep -o '"blacklist":\[[^]]*\]' | sed 's/"blacklist"://')
# 添加新IP
if [[ $BLACKLIST == "[]" ]]; then
NEW_BLACKLIST="[{\"ip\": \"$IP\", \"expire\": $EXPIRE, \"start_time\": $NOW}]"
else
NEW_BLACKLIST=$(echo $BLACKLIST | sed "s/\]/, {\"ip\": \"$IP\", \"expire\": $EXPIRE, \"start_time\": $NOW}\]/")
fi
# 更新元数据
NEW_META=$(echo $META_DATA | sed "s/\"blacklist\":\[[^]]*\]/\"blacklist\":$NEW_BLACKLIST/")
else
# 没有现有黑名单,创建新的
NEW_META=$(echo $META_DATA | sed "s/{/{\"blacklist\":[{\"ip\": \"$IP\", \"expire\": $EXPIRE, \"start_time\": $NOW}],/")
fi
# 更新配置
curl http://127.0.0.1:9180/apisix/admin/plugin_metadata/ip-blacklist -H "X-API-KEY: edd1c9f034335f136f87ad84b625c8f1" -X PUT -d "$NEW_META"
echo "IP $IP 已添加到黑名单,过期时间: $EXPIRE 秒"
总结
使用APISIX的Plugin Metadata机制实现IP黑名单功能是一种优雅的解决方案,完全符合章亦春的设计理念:
- 使用现有机制而非创建新资源类型
- 配置集中存储、易于管理
- 高性能设计
- 支持动态更新
这个实现可以轻松扩展支持更复杂的黑名单规则,如CIDR匹配、地理位置屏蔽等。

浙公网安备 33010602011771号