How to Ban/Suspend Users in Laravel Project

Laravel Auth system has a lot of features, but it doesn't include suspending users for some time, like banning some angry forum user for 14 days to calm down. Luckily, it's easy to implement, with Middleware. This article will show you how.

Here's what the banned user will see after they try to log in:

Step 1. New column: users.banned_until

Let's not just ban user with true/false field like is_banned, I would advise to have timestamp field - if it's null, then user is not banned, otherwise we know the date, until when.

As an example, we take fresh Laravel 5.7 project with default migrations and make:auth command. Next, we add this column:

php artisan make:migration add_banned_until_to_users_table

Migration file:

class AddBannedUntilToUsersTable extends Migration
{
    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->timestamp('banned_until')->nullable();
        });
    }

All already existing users will have field as NULL, so no one will be banned automatically after this migration, it's safe.

We also need to add that field to $fillable array in app/User.php model. For convenience, let's put it into $dates array, too - we will do some Carbon manipulations later.

class User extends Authenticatable
{
    protected $fillable = [
        'name', 'email', 'password', 'banned_until'
    ];

    protected $dates = [
        'banned_until'
    ];
}

For this article, I will skip the User administration part where administrator would ban/unban user - you can generate such user management system with our generator QuickAdminPanel.com.

In this article, we will assume that some admin somewhere puts the value on users.banned_until as timestamp or NULL. Maybe even directly in the database via Sequel Pro or phpMyAdmin.


Step 2. Middleware CheckBanned

We will create a middleware to check if the user is banned. In that case, we log them out and redirect back to login form with an error message.

php artisan make:middleware CheckBanned

Here's the file app/Http/Middleware/CheckBanned.php:

class CheckBanned
{
    public function handle($request, Closure $next)
    {
        if (auth()->check() && auth()->user()->banned_until && now()->lessThan(auth()->user()->banned_until)) {
            $banned_days = now()->diffInDays(auth()->user()->banned_until);
            auth()->logout();

            if ($banned_days > 14) {
                $message = 'Your account has been suspended. Please contact administrator.';
            } else {
                $message = 'Your account has been suspended for '.$banned_days.' '.str_plural('day', $banned_days).'. Please contact administrator.';
            }

            return redirect()->route('login')->withMessage($message);
        }

        return $next($request);
    }
}

A few things to notice here:

  • We use some Carbon methods like lessThan() or diffInDays() to perform date operations. That's why earlier we needed to add banned_until field as $dates property in User model.
  • If user is banned for 14 days or less, we show how many days of suspension are left. Otherwise we assume that the account is banned forever.
  • Not sure if you know about str_plural() method to show singular or plural form of the noun, depending on a number. Here's my old article about it.

Step 3. Using Middleware and Show Error Message

Next, we need to register this middleware to run on every request, so we add its class to app/Http/Kernel.php file group called web:

protected $middlewareGroups = [
    'web' => [
        \App\Http\Middleware\EncryptCookies::class,

        // ... other middleware classes

        \App\Http\Middleware\CheckBanned::class,
    ],

Finally, let's add the message in resources/views/auth/login.blade.php:

...

<div class="card-body">

    @if (session('message'))
        <div class="alert alert-danger">{{ session('message') }}</div>
    @endif

    <form method="POST" action="{{ route('login') }}">

...

Here's the visual result:

No comments yet…

Like our articles?

Become a Premium Member for $129/year or $29/month

Written by

You might also like