Skip to content

Middleware

Suspend provides several middleware options:

MiddlewareAliasDescription
CheckSuspendedMiddlewaresuspendedCheck if authenticated user is suspended
CheckIpMiddlewaresuspended.ipCheck if request IP is suspended
CheckContextMiddlewaresuspended.contextCheck multiple contexts at once
routes/web.php
use Illuminate\Support\Facades\Route;
// Check authenticated user
Route::middleware(['auth', 'suspended'])->group(function () {
Route::get('/dashboard', DashboardController::class);
Route::get('/profile', ProfileController::class);
});
// Check IP address
Route::middleware(['suspended.ip'])->group(function () {
Route::post('/api/signup', SignupController::class);
Route::post('/api/contact', ContactController::class);
});
class DashboardController extends Controller
{
public function __construct()
{
$this->middleware('suspended');
}
}

Configure middleware behavior in config/suspend.php:

'middleware' => [
// Automatically check IP against suspensions
'check_ip' => true,
// Automatically check country against suspensions
'check_country' => false,
// HTTP response code when suspended
'response_code' => 403,
// Response message when suspended
'response_message' => 'Access denied. Your access has been suspended.',
// Routes to exclude from checks
'except' => [
'login',
'logout',
'contact',
'suspended',
],
],

For API routes, return JSON instead of redirecting:

// Create a custom middleware
class ApiSuspendedMiddleware
{
public function handle(Request $request, Closure $next)
{
if (auth()->check() && Suspend::for(auth()->user())->isSuspended()) {
return response()->json([
'error' => 'suspended',
'message' => 'Your account has been suspended.',
], 403);
}
return $next($request);
}
}
class SuspendedRedirectMiddleware
{
public function handle(Request $request, Closure $next)
{
if (auth()->check()) {
$suspension = Suspend::for(auth()->user())->getActiveSuspension();
if ($suspension) {
return redirect()->route('suspended', [
'reason' => $suspension->reason,
'expires' => $suspension->expires_at?->diffForHumans(),
]);
}
}
return $next($request);
}
}
class SuspensionDetailsMiddleware
{
public function handle(Request $request, Closure $next)
{
if (!auth()->check()) {
return $next($request);
}
$suspensions = Suspend::for(auth()->user())->activeSuspensions();
if ($suspensions->isEmpty()) {
return $next($request);
}
$suspension = $suspensions->first();
return response()->view('suspended', [
'reason' => $suspension->reason,
'expires_at' => $suspension->expires_at,
'suspended_by' => $suspension->suspendedBy,
'can_appeal' => $this->canAppeal($suspension),
], 403);
}
private function canAppeal($suspension): bool
{
return !$suspension->metadata['permanent'] ?? false;
}
}

The context middleware checks multiple factors at once:

// Register in app/Http/Kernel.php
protected $routeMiddleware = [
'suspended.context' => CheckContextMiddleware::class,
];
Route::middleware(['suspended.context:email,ip,fingerprint'])->group(function () {
Route::post('/register', RegisterController::class);
});
'middleware' => [
'except' => [
'login',
'logout',
'password/*',
'suspended',
'api/health',
],
],
Route::middleware(['suspended:except:login,logout'])->group(function () {
// Routes here
});
class CheckSuspendedMiddleware
{
protected array $except = [
'login',
'logout',
'suspended',
];
public function handle(Request $request, Closure $next)
{
if ($this->shouldSkip($request)) {
return $next($request);
}
// Check suspension...
}
protected function shouldSkip(Request $request): bool
{
foreach ($this->except as $pattern) {
if ($request->is($pattern) || $request->routeIs($pattern)) {
return true;
}
}
return false;
}
}

Check suspensions by IP address for unauthenticated requests:

use Cline\Suspend\Facades\Suspend;
class CheckIpMiddleware
{
public function handle(Request $request, Closure $next)
{
$ip = $request->ip();
if (Suspend::check()->ip($ip)->matches()) {
abort(403, 'Your IP address has been blocked.');
}
return $next($request);
}
}

Block requests from specific countries:

use Cline\Suspend\Facades\Suspend;
class CheckCountryMiddleware
{
public function handle(Request $request, Closure $next)
{
$country = app('suspend.geo_resolver')->resolve($request->ip());
if ($country && Suspend::check()->country($country)->matches()) {
abort(403, 'Service not available in your region.');
}
return $next($request);
}
}

Prevent suspended contexts from registering new accounts:

class RegistrationController extends Controller
{
public function __construct()
{
$this->middleware(function (Request $request, Closure $next) {
$isSuspended = Suspend::check()
->email($request->input('email'))
->ip($request->ip())
->matches();
if ($isSuspended) {
return back()->withErrors([
'email' => 'Registration is not available.',
]);
}
return $next($request);
});
}
}

Combine suspension checks with rate limiting:

RateLimiter::for('api', function (Request $request) {
$ip = $request->ip();
// Suspended IPs get no rate limit quota
if (Suspend::check()->ip($ip)->matches()) {
return Limit::none();
}
return Limit::perMinute(60)->by($request->user()?->id ?: $ip);
});

Create middleware groups for common patterns:

app/Http/Kernel.php
protected $middlewareGroups = [
'web' => [
// ... other middleware
],
'protected' => [
'auth',
'suspended',
'verified',
],
'api.protected' => [
'auth:sanctum',
'suspended',
'throttle:api',
],
];

Use the groups:

Route::middleware('protected')->group(function () {
Route::get('/dashboard', DashboardController::class);
});
Route::middleware('api.protected')->prefix('api')->group(function () {
Route::get('/user', UserController::class);
});