getAppFromRequest($request); if (!$app) { return $this->forbiddenResponse('应用信息不存在'); } // 检查IP白名单 if (!$this->checkIpWhitelist($app, $request->ip())) { return $this->forbiddenResponse('IP地址不在白名单中'); } // 记录IP检查日志 $this->logIpCheck($app, $request); return $next($request); } /** * 从请求中获取应用信息 * * @param Request $request * @return OpenApiApp|null */ protected function getAppFromRequest(Request $request): ?OpenApiApp { // 从请求属性中获取应用信息(由认证中间件设置) return $request->attributes->get('openapi_app'); } /** * 检查IP白名单 * * @param OpenApiApp $app * @param string $ip * @return bool */ protected function checkIpWhitelist(OpenApiApp $app, string $ip): bool { // 获取应用的IP白名单配置 $ipWhitelist = $app->ip_whitelist ?? []; // 如果没有配置白名单,默认允许所有IP if (empty($ipWhitelist)) { return true; } // 检查IP是否在白名单中 foreach ($ipWhitelist as $allowedIp) { if ($this->matchIp($ip, $allowedIp)) { return true; } } return false; } /** * 匹配IP地址 * * @param string $ip 请求IP * @param string $pattern IP模式(支持CIDR、通配符等) * @return bool */ protected function matchIp(string $ip, string $pattern): bool { // 精确匹配 if ($ip === $pattern) { return true; } // CIDR格式匹配(如:192.168.1.0/24) if (str_contains($pattern, '/')) { return $this->matchCidr($ip, $pattern); } // 通配符匹配(如:192.168.1.*) if (str_contains($pattern, '*')) { return $this->matchWildcard($ip, $pattern); } // 范围匹配(如:192.168.1.1-192.168.1.100) if (str_contains($pattern, '-')) { return $this->matchRange($ip, $pattern); } return false; } /** * CIDR格式匹配 * * @param string $ip * @param string $cidr * @return bool */ protected function matchCidr(string $ip, string $cidr): bool { list($subnet, $mask) = explode('/', $cidr); $ipLong = ip2long($ip); $subnetLong = ip2long($subnet); $maskLong = -1 << (32 - (int)$mask); return ($ipLong & $maskLong) === ($subnetLong & $maskLong); } /** * 通配符匹配 * * @param string $ip * @param string $pattern * @return bool */ protected function matchWildcard(string $ip, string $pattern): bool { // 将通配符转换为正则表达式 $regex = str_replace(['*', '.'], ['[0-9]+', '\.'], $pattern); $regex = '/^' . $regex . '$/'; return preg_match($regex, $ip) === 1; } /** * 范围匹配 * * @param string $ip * @param string $range * @return bool */ protected function matchRange(string $ip, string $range): bool { list($start, $end) = explode('-', $range); $ipLong = ip2long($ip); $startLong = ip2long(trim($start)); $endLong = ip2long(trim($end)); return $ipLong >= $startLong && $ipLong <= $endLong; } /** * 记录IP检查日志 * * @param OpenApiApp $app * @param Request $request * @return void */ protected function logIpCheck(OpenApiApp $app, Request $request): void { Log::info("IP whitelist check passed", [ 'app_id' => $app->app_id, 'ip' => $request->ip(), 'whitelist' => $app->ip_whitelist, 'uri' => $request->getRequestUri(), 'method' => $request->getMethod(), 'user_agent' => $request->userAgent(), ]); } /** * 返回IP被拒绝响应 * * @param string $message * @return \Illuminate\Http\JsonResponse */ protected function forbiddenResponse(string $message) { return response()->json([ 'error' => 'ip_not_allowed', 'message' => $message, ], 403); } }