You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修改Laravel中间件代码,检查请求IP是否在子网掩码范围内?

如何修改Laravel中间件代码,检查请求IP是否在子网掩码范围内?

嘿,我来帮你搞定这个问题!你现在的代码只能匹配精确的单个IP,要支持像12.23.34.0/27这种带子网掩码的白名单条目,咱们得把原来的contains()判断逻辑换掉,改成能自定义匹配规则的方式。

直接上修改后的完整代码,你可以直接替换中间件里的判断部分:

$requestIP = $request->ip();
$whitelist = collect([
   '127.0.0.1',
   '12.23.34.0/27'
]);

// 遍历白名单,只要有一个条目匹配就通过
$isAuthorized = $whitelist->some(function ($entry) use ($requestIP) {
    // 处理普通单个IP的情况(不带子网掩码)
    if (strpos($entry, '/') === false) {
        return $entry === $requestIP;
    }

    // 处理带子网掩码的情况
    list($subnet, $prefix) = explode('/', $entry);
    
    // 把IP和子网都转成32位长整型,方便计算
    $ipLong = ip2long($requestIP);
    $subnetLong = ip2long($subnet);
    
    // 根据前缀长度计算子网掩码的长整型值
    $mask = -1 << (32 - (int)$prefix);
    
    // 通过按位与操作,对比IP和子网的网络部分是否一致
    return ($ipLong & $mask) === ($subnetLong & $mask);
});

if ($isAuthorized) {
    return $next($request);
}

abort(response('Unauthorized IP', 403));

我给你拆解下这段代码的逻辑:

  • 用some()方法代替原来的contains(),some()允许我们自定义匹配规则,只要白名单里有一个条目符合条件,就会返回true;
  • 对每个白名单条目做区分:
    • 如果是不带/的普通IP,直接和请求IP做精确对比;
    • 如果是带/的子网格式,先拆分出子网地址和前缀长度,然后把IP和子网都转成整数(ip2long()的作用),再计算子网掩码,最后通过按位与操作,判断请求IP是不是落在这个子网里;
  • 只要有一个条目匹配,就放行请求,否则返回403未授权。

另外给你提几个小建议:

  • 这段代码目前只支持IPv4,如果你的API需要兼容IPv6,得调整逻辑(ip2long()不支持IPv6),不过如果只用IPv4的话完全没问题;
  • 可以给子网格式的条目加个简单校验,比如确保拆分后有子网和前缀两个部分,前缀长度在0-32之间,避免非法格式导致报错;
  • 之后你要把白名单存到数据库的话,这个判断逻辑可以直接复用,只需要从数据库取出所有IP/子网条目,再用同样的方式遍历判断就行。

备注:内容来源于stack exchange,提问作者Danny Connolly

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.15 09:17:58