PHP项目Laravel维护模式排除IP

wen PHP项目 3

本文目录导读:

PHP项目Laravel维护模式排除IP

  1. 使用预定义 IP 白名单(最简单)
  2. 使用中间件方式(推荐)
  3. 使用 Laravel 的 php artisan down 命令
  4. .env 文件中配置
  5. 创建维护模式视图
  6. 高级方案:使用 Redis 动态管理 IP
  7. 推荐使用方案

在 Laravel 中设置维护模式并排除特定 IP,有多种方法,以下是详细的解决方案:

使用预定义 IP 白名单(最简单)

bootstrap/app.php 中配置:

<?php
$app = new Illuminate\Foundation\Application(
    $_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)
);
// 配置维护模式排除的 IP
$app->configure('app');
return $app->createApplication(function ($app) {
    // 在维护模式下允许访问的 IP 列表
    $app->make(Illuminate\Contracts\Http\Kernel::class)
        ->setMaintenanceModeHandler(function () {
            // 定义允许访问的 IP
            $allowedIPs = [
                '127.0.0.1',      // 本地
                '192.168.1.100',  // 办公室 IP
                '103.21.58.61',   // 特定 IP
            ];
            $currentIP = request()->ip();
            if (in_array($currentIP, $allowedIPs)) {
                return response()->make('', 200);
            }
            // 返回维护模式页面
            return response()->make(
                view('errors.maintenance'),
                503,
                ['Retry-After' => 3600]
            );
        });
});

使用中间件方式(推荐)

创建自定义维护模式中间件

php artisan make:middleware CheckMaintenanceMode

中间件代码

<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode as Middleware;
class CheckMaintenanceMode extends Middleware
{
    /**
     * 允许访问的 IP 地址列表
     */
    protected $allowedIPs = [
        '127.0.0.1',
        '192.168.1.0/24',    // 支持 CIDR 格式
        '103.21.58.61',
    ];
    /**
     * 处理请求
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        // 如果应用处于维护模式且当前 IP 不在白名单中
        if ($this->app->isDownForMaintenance() && 
            !$this->isAllowedIP($request->ip())) {
            return response()->json([
                'message' => '系统正在维护中,请稍后再试',
                'code' => 503
            ], 503);
        }
        return $next($request);
    }
    /**
     * 检查 IP 是否在允许列表中
     */
    protected function isAllowedIP($ip)
    {
        foreach ($this->allowedIPs as $allowedIP) {
            if ($this->ipMatches($ip, $allowedIP)) {
                return true;
            }
        }
        return false;
    }
    /**
     * 检查 IP 匹配(支持通配符和 CIDR)
     */
    protected function ipMatches($ip, $allowedIP)
    {
        // 完全匹配
        if ($ip === $allowedIP) {
            return true;
        }
        // 支持 * 通配符,如 192.168.*.*
        if (strpos($allowedIP, '*') !== false) {
            $pattern = str_replace('*', '(.*)', preg_quote($allowedIP, '/'));
            return (bool) preg_match("/^{$pattern}$/", $ip);
        }
        // 支持 CIDR 格式,如 192.168.1.0/24
        if (strpos($allowedIP, '/') !== false) {
            return $this->ipInCidr($ip, $allowedIP);
        }
        return false;
    }
    /**
     * 检查 IP 是否在 CIDR 范围内
     */
    protected function ipInCidr($ip, $cidr)
    {
        list($subnet, $bits) = explode('/', $cidr);
        if ($bits == 0) {
            $bits = 32;
        }
        $ip = ip2long($ip);
        $subnet = ip2long($subnet);
        $mask = -1 << (32 - $bits);
        $subnet &= $mask;
        return ($ip & $mask) == $subnet;
    }
}

注册中间件

app/Http/Kernel.php 中注册:

protected $middleware = [
    // ...
    \App\Http\Middleware\CheckMaintenanceMode::class,
];

使用 Laravel 的 php artisan down 命令

# 启用维护模式,排除特定 IP
php artisan down --allow=127.0.0.1 --allow=192.168.1.0/24
# 或者使用配置文件
php artisan down --allow=103.21.58.61

查看当前维护模式状态

php artisan down --status

.env 文件中配置

.env 文件中添加:

MAINTENANCE_ALLOWED_IPS=127.0.0.1,192.168.1.100,103.21.58.61

然后在代码中使用:

$allowedIPs = explode(',', env('MAINTENANCE_ALLOWED_IPS', ''));
protected function setUpMaintenanceMode()
{
    if ($this->app->isDownForMaintenance()) {
        $allowedIPs = explode(',', env('MAINTENANCE_ALLOWED_IPS', ''));
        if (!in_array(request()->ip(), $allowedIPs)) {
            abort(503, '系统维护中');
        }
    }
}

创建维护模式视图

创建 resources/views/errors/maintenance.blade.php

<!DOCTYPE html>
<html>
<head>系统维护中</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            text-align: center;
            padding: 50px;
            background: #f5f5f5;
        }
        .maintenance-box {
            background: white;
            padding: 40px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
            max-width: 600px;
            margin: 100px auto;
        }
        h1 {
            color: #333;
            margin-bottom: 20px;
        }
        p {
            color: #666;
            line-height: 1.6;
        }
    </style>
</head>
<body>
    <div class="maintenance-box">
        <h1>🔧 系统维护中</h1>
        <p>系统正在进行维护升级,预计将在 <strong>30分钟</strong> 内完成。</p>
        <p>给您带来的不便,敬请谅解!</p>
    </div>
</body>
</html>

高级方案:使用 Redis 动态管理 IP

<?php
namespace App\Services;
use Illuminate\Support\Facades\Redis;
class MaintenanceModeManager
{
    protected $redis;
    public function __construct()
    {
        $this->redis = Redis::connection();
    }
    public function addAllowedIP($ip)
    {
        $this->redis->sadd('maintenance:allowed_ips', $ip);
    }
    public function removeAllowedIP($ip)
    {
        $this->redis->srem('maintenance:allowed_ips', $ip);
    }
    public function isAllowed($ip)
    {
        return $this->redis->sismember('maintenance:allowed_ips', $ip);
    }
    public function getAllowedIPs()
    {
        return $this->redis->smembers('maintenance:allowed_ips');
    }
}

推荐使用方案

对于大多数项目,推荐使用方案 2(中间件方式),因为:

  1. 代码清晰,易于维护
  2. 支持复杂的 IP 匹配逻辑(通配符、CIDR)
  3. 可以自定义响应格式
  4. 方便切换功能

记得在生产环境测试时,确保你当前的 IP 在白名单中,否则可能会被锁在外面!

抱歉,评论功能暂时关闭!