thinkphp中可通过全局中间件、路由中间件、配置文件或数据库实现管理员ip白名单;推荐优先使用全局中间件配合cidr匹配,并从配置文件动态读取白名单以提升可维护性与安全性。

如果您在ThinkPHP项目中需要限制仅特定IP地址可访问管理员后台接口或路由,则可能是由于管理员操作需更高安全等级,防止未授权访问。以下是实现管理员IP白名单的多种配置方法:
一、通过全局中间件实现IP白名单拦截
该方法在请求进入路由匹配前即完成IP校验,执行时机早、安全性高,适用于所有管理员相关URL路径(如 /admin/*、/api/admin/*)。必须将中间件注册在 app/middleware.php 的全局中间件数组开头,确保其优先执行;若误配在 route/app.php 中,中间件将完全不生效。
1、在 app/middleware.php 文件中,将自定义中间件添加至数组最前端,例如:
return [
app\middleware\AdminIpWhitelist::class,
// 其他中间件...
];
2、创建中间件类 app/middleware/AdminIpWhitelist.php,内容如下:
public function handle($request, Closure $next)
{
$url = $request->url(true);
$clientIp = $request->ip();
$whitelist = ['127.0.0.1', '192.168.10.50', '203.0.113.25/32'];
if (!$this->isInWhitelist($clientIp, $whitelist) || !str_starts_with($url, '/admin/') && !str_starts_with($url, '/api/admin/')) {
return json(['code' => 403, 'msg' => 'forbidden'])->code(403);
}
return $next($request);
}
3、在同一个类中实现 CIDR 匹配辅助方法:
private function isInWhitelist($ip, $list)
{
foreach ($list as $rule) {
if (strpos($rule, '/') === false) {
if ($ip === $rule) return true;
} else {
list($subnet, $bits) = explode('/', $rule);
$ipLong = ip2long($ip);
$subnetLong = ip2long($subnet);
$mask = -1 if (($ipLong & $mask) === ($subnetLong & $mask)) return true;
}
}
return false;
}
二、通过Nginx配置限制管理员入口目录访问
该方法在Web服务器层完成过滤,不依赖PHP执行,性能最优且能有效阻止恶意扫描抵达应用层。适用于部署在宝塔、LNMP等Nginx环境,且管理员后台有独立路径(如 /admin/ 或 /manager/)。
1、登录宝塔面板,进入对应网站的【设置】→【配置文件】选项卡。
2、在 server 块内、任意 location 块外(推荐放在 server 块顶部),插入以下指令:
location ^~ /admin/ {
allow 114.114.114.114;
allow 2001:db8::/32;
deny all;
}
3、点击【保存】并执行【重载配置】。注意:若管理员路径为 /public/admin/,则 location 应写为 ^~ /public/admin/;路径必须与实际访问URL严格一致。
三、通过ThinkPHP路由绑定中间件实现细粒度控制
该方法适用于仅对部分管理员路由启用白名单,不影响其他后台功能。需在路由定义时显式绑定中间件,避免全局影响。中间件逻辑可复用前述 AdminIpWhitelist 类,但仅作用于指定路由组。
1、在 route/app.php 中定义管理员路由组,并绑定中间件:
Route::group('admin', function () {
Route::get('dashboard', 'admin.index/dashboard');
Route::post('user/edit', 'admin.user/edit');
})->middleware(appmiddlewareAdminIpWhitelist::class);
2、确保该中间件类中校验逻辑仅针对当前请求URL前缀,例如:
if (!str_starts_with($url, '/admin/')) {
return $next($request); // 非管理员路径直接放行
}
3、在中间件 handle 方法末尾添加明确放行语句:
return $next($request);
四、通过配置文件动态管理白名单列表
该方法便于生产环境维护,避免硬编码导致配置变更需重新部署。白名单数据从 config/route.php 统一读取,支持热更新(需清除runtime/cache/下的配置缓存)。
1、在 config/route.php 中新增配置项:
'admin_ip_whitelist' => [
'127.0.0.1',
'10.10.0.0/16',
'2001:db8:abcd::/48'
],
2、在中间件中使用 Config::get('route.admin_ip_whitelist') 替代硬编码数组。
3、调试时可在中间件开头加入日志记录:
trace('Admin IP check: ' . $clientIp . ' against ' . json_encode(Config::get('route.admin_ip_whitelist')));
五、通过数据库查询实现动态白名单策略
该方法适用于需按管理员账号、角色或时段动态调整白名单的场景。需确保查询逻辑轻量,避免拖慢所有请求;建议对白名单数据做内存缓存(如使用 thinkCache::store('redis')->get())。
1、创建数据表 admin_ip_policy,字段包括 id、admin_id、ip_rule(VARCHAR)、status(TINYINT)、created_at。
2、在中间件中构造查询条件:
$policy = Db::name('admin_ip_policy')
->where('status', 1)
->where('ip_rule', 'like', $clientIp . '%')
->find();
3、若未命中,再执行 CIDR 精确匹配循环;匹配成功后立即返回 $next($request)。
4、关键提示:禁止在中间件中执行未加索引的全表模糊查询或 JOIN 操作,否则将引发严重性能瓶颈。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











