PHP 设置正则
<?php namespace MainController; use KIFCacheDisRedis; use KIFCoreRequest; /** * 涉及文件 * /export/manager/ybyl/main/config/route.inc.php * /export/manager/ybyl/main/lib/Controller/QiniuAuth.class.php * */ <<<EOF 禁止ip设置 查看禁止ip列表 /usr/local/php7.4/bin/php /export/manager/ybyl/main/www/index.php -c=QiniuAuth -a=list 增加 /usr/local/php7.4/bin/php /export/manager/ybyl/main/www/index.php -c=QiniuAuth -a=add -i=2408:84e1:60:*:*:*:*:* 删除 /usr/local/php7.4/bin/php /export/manager/ybyl/main/www/index.php -c=QiniuAuth -a=del -i=IP1,IP2 清除所有配置 /usr/local/php7.4/bin/php /export/manager/ybyl/main/www/index.php -c=QiniuAuth -a=clearAll EOF; class QiniuAuth extends Controller { protected $objDisRedis; protected $bannedIpKey = 'bannedips'; protected $bannedIpPreg = 'ip_blacklist_preg'; public function __construct() { $this->objDisRedis = new DisRedis(); } /** * * /?c=qiniuAuth * 七牛cdn鉴权 * 'HTTP_CIP' => '106.3.135.101', * 'HTTP_CIP' => '2408:84e1:60:4979:2d11:d97e:a7c0:b0d7', * // 'HTTP_AUTHFROM' => 'qiniu', * */ public function doDefault() { $userip = $_SERVER['HTTP_CIP']; $preg = $this->objDisRedis->get($this->bannedIpPreg); if (!$userip || $preg && preg_match($preg, $userip)) { header("HTTP/1.0 401 Unauthorized"); header("Status: 401 Unauthorized"); exit(); } else { header("HTTP/1.0 200 OK"); header("Status: 200 OK"); exit(); } } /** * /usr/local/php7.4/bin/php /export/manager/xx/main/www/index.php -c=QiniuAuth -a=Add -i= * 添加限制访问ip, 支持多个 * 界面: 以换行符分割, 命令行: 以逗号分割 * // hash 表 */ public function doAdd() { if (Request::isCLI()) { $opts = getopt('a:c:i:'); $ips = $opts['i']; $ips = explode(',', $ips); } else { $ips = Request::p('ips'); $ips = explode(" ", $ips); } $ips = array_filter($ips); if (empty($ips)) { $this->ajax_fail_exit('no ips'); } foreach ($ips as $ip) { $this->objDisRedis->hSet($this->bannedIpKey, $ip, time()); } $setRes = $this->setBannedIpPreg(); if(!$setRes) { $this->ajax_fail_exit('cache ip preg error'); } $this->ajax_success_exit('success'); } /** * * 删除限制访问ip, 支持多个 * 界面: 以换行符分割, 命令行: 以逗号分割 * // hash 表 */ public function doDel() { if (Request::isCLI()) { $opts = getopt('a:c:i:'); $ips = $opts['i']; $ips = explode(',', $ips); } else { $ips = Request::p('ips'); $ips = explode(" ", $ips); } $ips = array_filter($ips); if (empty($ips)) { $this->ajax_fail_exit('no ips'); } $res = $this->objDisRedis->hDel($this->bannedIpKey, $ips); $setRes = $this->setBannedIpPreg(); if(!$setRes) { $this->ajax_fail_exit('cache ip preg error'); } if ($res) { $this->ajax_success_exit('success'); } else { $this->ajax_fail_exit('fail'); } } /** * 清除所有配置 */ public function doClearAll() { $res = $this->objDisRedis->del([$this->bannedIpPreg, $this->bannedIpKey]); if ($res) { $this->ajax_success_exit('clear success'); } else { $this->ajax_fail_exit('clear fail'); } } /** * 列出所有设置的 */ public function doList() { $ips = $this->objDisRedis->hGetAll($this->bannedIpKey); $str = "Ip 添加时间" . PHP_EOL; foreach($ips as $ip => $addTime) { $str .= $ip . " " . date('Y-m-d H:i:s', $addTime) . PHP_EOL; } echo $str; echo PHP_EOL; echo 'preg: ' . PHP_EOL; echo $this->objDisRedis->get($this->bannedIpPreg); echo PHP_EOL; echo PHP_EOL; } protected function setBannedIpPreg() { $ips = $this->objDisRedis->hGetAll($this->bannedIpKey); $bannedIps = array_keys($ips); $str = ''; if(!empty($bannedIps)) { $str = implode('|', $bannedIps); $str = '(' . $str . ')'; // for php // $str = str_replace('.', '.', $str); // $str = str_replace('*', '.*', $str); // for lua $str = str_replace('.', '.', $str); $str = str_replace('*', '[wW]+', $str); } return $this->objDisRedis->set($this->bannedIpPreg, $str); } public function display() { return $this->render(); } }
nginx 配置
worker_processes 1; error_log logs/error.log; events { worker_connections 1024; } http { lua_package_path /usr/local/openresty/nginx/lua/lua-resty-redis/lib/resty/redis.lua; lua_shared_dict ip_blacklist 1m; server { listen 8080; location / { default_type text/html; access_by_lua_file lua/ip_blacklist.lua; content_by_lua_block { ngx.say("<p>hello, world</p>") } } } }
lua脚本
ip_blacklist.lua 只返回状态码, 七牛cdn鉴权用
local redis_host = "127.0.0.1" local redis_port = 6379 local redis_db = 0; local redis_auth = "17kb.com" -- connection timeout for redis in ms. don't set this too high! local redis_connection_timeout = 100 -- check a set with this key for blacklist entries local redis_key = "ip_blacklist_preg" -- cache lookups for this many seconds local cache_ttl = 60 -- end configuration local ip = ngx.var.remote_addr local ip_blacklist = ngx.shared.ip_blacklist local last_update_time = ip_blacklist:get("last_update_time"); 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.log(ngx.DEBUG, "Redis connection error while retrieving ip_blacklist:"); else local res, err = red:auth(redis_auth) if not res then -- ngx.log(ngx.DEBUG, "failed to authenticate: " .. err); else red:select(redis_db) local new_ip_blacklist_preg, err = red:get(redis_key); if err then -- ngx.log(ngx.DEBUG, "Redis read error while retrieving ip_blacklist:" .. err); else -- replace the locally stored ip_blacklist with the updated values: ip_blacklist:flush_all(); ip_blacklist:set(redis_key, new_ip_blacklist_preg); -- update time ip_blacklist:set("last_update_time", ngx.now()); end end end end local regex = ip_blacklist:get(redis_key) if regex then local m = ngx.re.match( ip, regex, "oj") if m then return ngx.exit(401); else return ngx.exit(200); end else return ngx.exit(200); end