solution-forest/filament-firewall
Filament Firewall adds IP whitelist/blacklist protection for your Laravel app and Filament admin panel. Includes install command, config and migrations, plus middleware (e.g., WhitelistRangeMiddleware) to restrict access by allowed/blocked ranges.
Filament\Actions\ActionRegistered) for dynamic firewall rule application, reducing hardcoding.config/filament-firewall.php, enabling environment-specific policies (e.g., dev/staging/prod).geoip2 (via league/geoip2), requiring minimal setup if not already in the stack.throttle middleware if needed.league/geoip2 (v3.x), MaxMind GeoLite2 database.spatie/geoip (alternative) or cloud-based services (e.g., IP2Location).Illuminate\Support\Facades\Cache with TTL (e.g., 1 hour).auth, verified) to avoid conflicts.composer require solution-forest/filament-firewall
php artisan vendor:publish --provider="SolutionForest\FilamentFirewall\FilamentFirewallServiceProvider"
config/filament-firewall.php:
'whitelist' => [
'192.168.1.0/24', // Office subnet
'US', 'GB', // Countries (requires GeoIP2)
],
'blacklist' => [
'1.2.3.4', // Malicious IP
'RU', 'CN', // Restricted countries
],
app/Http/Kernel.php (global) or Filament-specific routes:
protected $middleware = [
\SolutionForest\FilamentFirewall\Middleware\Firewall::class,
];
Filament\Contracts\Plugin hooks) for runtime rule updates.filament/spatie-laravel-permission) if rules are merged logically.$firewall->extend(function ($request) {
\Log::info("Firewall check for IP: {$request->ip()}");
});
filament/testing to mock requests:
$response = $this->actingAs($user)
->withHeaders(['X-Forwarded-For' => '192.168.1.100'])
->get('/admin');
spatie/laravel-geoip for managed updates.Pages\Settings to expose a UI for admins to edit rules (extend the package or build a custom panel).config/filament-firewall.php via Git.solution-forest/filament-firewall for Filament 4.x compatibility.league/geoip2 to avoid breaking changes.403 response (extend Firewall::class) to include helpful messages (e.g., "Access denied from your location").public function handle($request, Closure $next)
{
if ($this->isBlocked($request)) {
return response()->view('filament::firewall.blocked', [], 403);
}
return $next($request);
}
\Log::channel('security')->info('Firewall blocked', [
'ip' => $request->ip(),
'country' => $this->getCountry($request),
'user_agent' => $request->userAgent(),
]);
$country = Cache::remember("geoip:{$ip}", 3600, function () use ($ip) {
return $this->geoip->getCountry($ip);
});
spatie/geoip for cloud-based lookups if multi-region.firewall_rules table and query via Eloquent (avoid regex in middleware).| Failure Scenario | Impact | Mitigation |
|---|---|---|
| GeoIP2 database missing/corrupt | All geolocation rules fail | Fallback to IP-only rules; auto-repair script. |
| MaxMind API rate-limited | Increased latency or blocks | Cache aggressively; use local database. |
| Misconfigured whitelist/blacklist | Legitimate users blocked | Rollback config; implement approval workflow. |
| Middleware crashes | 500 errors for all requests | Wrap in try-catch; log errors to Sentry. |
| Redis cache stale | Outdated geolocation data | Short TTL (1 hour) + periodic cache invalidation. |
How can I help you explore Laravel packages today?