I did it in a more customizable way, based on a solution I used in L10.
In my case I use akaunting/laravel-setting, and in my admin panel I have fields to specify IP addresses and specific URLs that I can choose not to be affected by Maintenance Mode.
Create a middleware
php artisan make:middleware PreventRequestsDuringMaintenance
Here I manually define that Laravel uses my custom Middleware instead of the default one.
//bootstrap/app.php
->withMiddleware(function (Middleware $middleware) {
$middleware->use([
// \Illuminate\Http\Middleware\TrustHosts::class,
\Illuminate\Http\Middleware\TrustProxies::class,
\Illuminate\Http\Middleware\HandleCors::class,
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
\Illuminate\Http\Middleware\ValidatePostSize::class,
\Illuminate\Foundation\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
]);
})
App\Http\Middleware\PreventRequestsDuringMaintenance.php
namespace App\Http\Middleware;
use Closure;
use ErrorException;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\IpUtils;
use Symfony\Component\HttpKernel\Exception\HttpException;
class PreventRequestsDuringMaintenance extends \Illuminate\Foundation\Http\Middleware\PreventRequestsDuringMaintenance
{
/**
* Custom Allowed IP's
* @var array
*/
protected $excluded_ips = [];
/**
* Create a new middleware instance.
*
* @param Application $app
* @return void
*/
public function __construct(Application $app)
{
$this->app = $app;
$urls_allowed = collect(setting('maintenance_excluded_uris'))
->mapWithKeys(function ($uri) {
return explode(',', $uri);
})->toArray();
$ips_allowed = collect(setting('maintenance_excluded_ips'))
->mapWithKeys(function ($ip) {
return explode(',', $ip);
})->toArray();
// Auto add backend to excluded URIs
$this->except[] = '/' . config('mycustomconfig.backend_prefix') . '*';
$this->except = array_merge($this->except, $urls_allowed);
$this->excluded_ips = $ips_allowed;
}
/**
* Handle an incoming request.
*
* @param Request $request
* @param Closure $next
* @return mixed
*
* @throws HttpException
* @throws ErrorException
*/
public function handle($request, Closure $next)
{
if ($this->inExceptArray($request)) {
return $next($request);
}
if ($this->app->maintenanceMode()->active()) {
try {
$data = $this->app->maintenanceMode()->data();
} catch (ErrorException $exception) {
if (! $this->app->maintenanceMode()->active()) {
return $next($request);
}
throw $exception;
}
if (isset($data['secret']) && $request->path() === $data['secret']) {
return $this->bypassResponse($data['secret']);
}
if ($this->hasValidBypassCookie($request, $data) || $this->inExceptArray($request) ||
$this->inExceptIpArray($request)) {
return $next($request);
}
if (isset($data['redirect'])) {
$path = $data['redirect'] === '/'
? $data['redirect']
: trim($data['redirect'], '/');
if ($request->path() !== $path) {
return redirect($path);
}
}
if (isset($data['template'])) {
return response(
$data['template'],
$data['status'] ?? 503,
$this->getHeaders($data)
);
}
throw new HttpException(
$data['status'] ?? 503,
'Service Unavailable',
null,
$this->getHeaders($data)
);
}
return $next($request);
}
/**
* @param $request
* @return bool
*/
private function inExceptIpArray($request)
{
// Check IP's on settings
return isset($this->excluded_ips) && IpUtils::checkIp($request->ip(), (array)$this->excluded_ips);
}
If anyone has any corrections or improvements, please comment.