DEV Community

Cover image for Laravel: Approve New Registered Users from Administrator
Povilas Korop
Povilas Korop

Posted on

Laravel: Approve New Registered Users from Administrator

Laravel framework comes with built-in Auth system, which is pretty good. But it doesn't cover all the cases, and the most common one is administrator approval of every new registered user. In this article, I will show you how to do it in fresh Laravel 5.7 project.

What we will cover:

  1. Preparing DB structure: migrations, models and seeders
  2. Restricting new users from accessing dashboard
  3. Notifying administrator about new user
  4. Approving new user by administrator

First, let's create a new Laravel project:

laravel new laravel
Enter fullscreen mode Exit fullscreen mode

Then you need to configure our .env file with database credentials.

Next, let's generate our Login/Register links:

php artisan make:auth
Enter fullscreen mode Exit fullscreen mode

So we can log in with this form:

Laravel login auth

From users DB table perspective, we need to add two fields:

  • admin (boolean, 0/1) - you may have more complicated logic with roles/permissions
  • approved_at (timestamp, nullable) - will be set to current timestamp when approved

So:

php artisan make:migration add_admin_to_users_table
Enter fullscreen mode Exit fullscreen mode

And then the migration itself:

Schema::table('users', function (Blueprint $table) {
    $table->boolean('admin')->default(false);
    $table->timestamp('approved_at')->nullable();
});

Enter fullscreen mode Exit fullscreen mode

Also, we need to add those fields into $fillable array in app/User.php model:

protected $fillable = [
    'name', 'email', 'password', 'admin', 'approved_at'
];
Enter fullscreen mode Exit fullscreen mode

Seeding admin user

This command will help us:

php artisan make:seeder AdminSeeder
Enter fullscreen mode Exit fullscreen mode

It will generate a new file in database/seeds folder, which we fill like this:

class AdminSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        \App\User::create([
            'name' => 'Admin',
            'email' => 'admin@admin.com',
            'email_verified_at' => now(),
            'password' => bcrypt('verysafepassword'),
            'admin' => 1,
            'approved_at' => now(),
        ]);
    }
}

Enter fullscreen mode Exit fullscreen mode

Finally, we need to add this class to the main database/seeds/DatabaseSeeder.php file.

public function run()
{
    $this->call(AdminSeeder::class);
}
Enter fullscreen mode Exit fullscreen mode

Now, we're ready with our DB structure and can run this:

php artisan migrate --seed
Enter fullscreen mode Exit fullscreen mode

At this point, if we log in with credentials admin@admin.com - verysafepassword, we should see our empty Home Dashboard, from default Laravel.

Laravel auth home dashboard


Restricting New User from Dashboard

Ok, now we can register with new user which will be not approved. Let's restrict them from accessing the actual dashboard.

First, we create a separate Blade file which will have text like "Waiting for approval". This will be a page we will redirect to, for every request of non-approved user.

So, resources/views/approval.blade.php:

@extends('layouts.app')

@section('content')
    <div class="container">
        <div class="row justify-content-center">
            <div class="col-md-8">
                <div class="card">
                    <div class="card-header">Waiting for Approval</div>

                    <div class="card-body">
                        Your account is waiting for our administrator approval.
                        <br />
                        Please check back later.
                    </div>
                </div>
            </div>
        </div>
    </div>
@endsection

Enter fullscreen mode Exit fullscreen mode

Next, we create a Controller to point to it. Or, in fact, we create a method in the same HomeController:

public function approval()
{
    return view('approval');
}

Enter fullscreen mode Exit fullscreen mode

Here's how it looks:

Laravel user approve

Finally, we need a route for it. Let's put it under auth middleware, and our routes/web.php will look like this:

Route::middleware(['auth'])->group(function () {
    Route::get('/approval', 'HomeController@approval')->name('approval');
    Route::get('/home', 'HomeController@index')->name('home');
});

Enter fullscreen mode Exit fullscreen mode

Now, we need to restrict the access for non-approved users to that /home URL. We create a new Middleware:

php artisan make:middleware CheckApproved
Enter fullscreen mode Exit fullscreen mode

It generates a file app/Http/Middleware/CheckApproved.php which we fill like this:

namespace App\Http\Middleware;

use Closure;

class CheckApproved
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if (!auth()->user()->approved_at) {
            return redirect()->route('approval');
        }

        return $next($request);
    }
}
Enter fullscreen mode Exit fullscreen mode

We need to register that Middleware in app/Http/Kernel.php in the $routeMiddleware array:

protected $routeMiddleware = [
    'auth' => \App\Http\Middleware\Authenticate::class,
    // ...
    'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
    'approved' => \App\Http\Middleware\CheckApproved::class,
];

Enter fullscreen mode Exit fullscreen mode

Finally, we add the home route to the block under that Middleware, so our routes/web.php now looks like this:

Route::middleware(['auth'])->group(function () {
    Route::get('/approval', 'HomeController@approval')->name('approval');

    Route::middleware(['approved'])->group(function () {
        Route::get('/home', 'HomeController@index')->name('home');
    });
});

Enter fullscreen mode Exit fullscreen mode

So now, every new user, after logging in, or on any action, will be redirected to the approval page.


Notifying Administrator About New User

We will use Laravel Notifications function that comes with the framework.

Let's generate a new Notification class:

php artisan make:notification NewUser
Enter fullscreen mode Exit fullscreen mode

Then we fill in a newly generated app/Notifications/NewUser.php:

namespace App\Notifications;

use App\User;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;

class NewUser extends Notification
{
    use Queueable;

    private $new_user;

    /**
     * Create a new notification instance.
     *
     * @return void
     */
    public function __construct(User $new_user)
    {
        $this->new_user = $new_user;
    }


    /**
     * Get the mail representation of the notification.
     *
     * @param  mixed  $notifiable
     * @return \Illuminate\Notifications\Messages\MailMessage
     */
    public function toMail($notifiable)
    {
        return (new MailMessage)
            ->line('New user has registered with email ' . $this->new_user->email)
            ->action('Approve user', route('admin.users.approve', $this->new_user->id));
    }

}

Enter fullscreen mode Exit fullscreen mode

A few things to notice here:

  • We will pass new registered user as an object via __construct() method, then it turns into a local private variable, which we will use in toMail() method as $this->new_user;
  • We specify the route to approve user, and we will create the functionality a little later below.

Now, to use this Notification, we will extend a controller app/Http/Controllers/Auth/RegisterController.php, specifically method create():

// Don't forget to add this
use App\Notifications\NewUser;

// ...

/**
 * Create a new user instance after a valid registration.
 *
 * @param  array  $data
 * @return \App\User
 */
protected function create(array $data)
{
    $user = User::create([
        'name' => $data['name'],
        'email' => $data['email'],
        'password' => Hash::make($data['password']),
    ]);

    $admin = User::where('admin', 1)->first();
    if ($admin) {
        $admin->notify(new NewUser($user));
    }

    return $user;
}

Enter fullscreen mode Exit fullscreen mode

To test sending of an email, I recommend MailTrap which I will use and put its credentials to Laravel .env file:

MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=54043xxxxxxxxxx
MAIL_PASSWORD=a7d17xxxxxxxxx
MAIL_ENCRYPTION=null
Enter fullscreen mode Exit fullscreen mode

So, on every new user, admin will get something like this:

Laravel mailtrap email


Approving New User by Administrator

In previous step, we've used a route: route('admin.users.approve', $this->new_user->id), now let's actually implement it.

We actually need two routes: to list the users, and to approve one of them.
Also, we need to restrict it for admin users only, so let's generate another middleware:

php artisan make:middleware CheckAdmin
Enter fullscreen mode Exit fullscreen mode

We fill the new file app/Http/Middleware/CheckAdmin.php:

namespace App\Http\Middleware;

use Closure;

class CheckAdmin
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if (!auth()->user()->admin) {
            return redirect()->route('home');
        }

        return $next($request);
    }
}
Enter fullscreen mode Exit fullscreen mode

We also need to add it to app/Http/Kernel.php array, as above:

protected $routeMiddleware = [
    'auth' => \App\Http\Middleware\Authenticate::class,
    // ...
    'approved' => \App\Http\Middleware\CheckApproved::class,
    'admin' => \App\Http\Middleware\CheckAdmin::class,
];
Enter fullscreen mode Exit fullscreen mode

Finally, here's our final routes/web.php version:

Route::middleware(['auth'])->group(function () {
    Route::get('/approval', 'HomeController@approval')->name('approval');

    Route::middleware(['approved'])->group(function () {
        Route::get('/home', 'HomeController@index')->name('home');
    });

    Route::middleware(['admin'])->group(function () {
        Route::get('/users', 'UserController@index')->name('admin.users.index');
        Route::get('/users/{user_id}/approve', 'UserController@approve')->name('admin.users.approve');
    });
});
Enter fullscreen mode Exit fullscreen mode

Last thing we need is to implement the actual approval.

php artisan make:controller UserController
Enter fullscreen mode Exit fullscreen mode

Here's the code for app/Http/Controllers/UserController.php:

namespace App\Http\Controllers;

use App\User;

class UserController extends Controller
{

    public function index()
    {
        $users = User::whereNull('approved_at')->get();

        return view('users', compact('users'));
    }

    public function approve($user_id)
    {
        $user = User::findOrFail($user_id);
        $user->update(['approved_at' => now()]);

        return redirect()->route('admin.users.index')->withMessage('User approved successfully');
    }

}
Enter fullscreen mode Exit fullscreen mode

So method approve() will approve user and redirect back to the list. Which is implemented in resources/views/users.blade.php:

@extends('layouts.app')

@section('content')
    <div class="container">
        <div class="row justify-content-center">
            <div class="col-md-8">
                <div class="card">
                    <div class="card-header">Users List to Approve</div>

                    <div class="card-body">

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

                        <table class="table">
                            <tr>
                                <th>User name</th>
                                <th>Email</th>
                                <th>Registered at</th>
                                <th></th>
                            </tr>
                            @forelse ($users as $user)
                                <tr>
                                    <td>{{ $user->name }}</td>
                                    <td>{{ $user->email }}</td>
                                    <td>{{ $user->created_at }}</td>
                                    <td><a href="{{ route('admin.users.approve', $user->id) }}"
                                           class="btn btn-primary btn-sm">Approve</a></td>
                                </tr>
                            @empty
                                <tr>
                                    <td colspan="4">No users found.</td>
                                </tr>
                            @endforelse
                        </table>
                    </div>
                </div>
            </div>
        </div>
    </div>
@endsection
Enter fullscreen mode Exit fullscreen mode

Final visual result:

Laravel administrator approve users

So here's probably the quickest way to approve new registered users in Laravel. Pretty simple, huh?

Top comments (11)

Collapse
 
dm_254 profile image
Douglas Mandela

Argument 1 passed to App\Notifications\NewUser::__construct() must be an instance of App\Notifications\User, instance of App\User given, called in /var/www/html/adminApprove/app/Http/Controllers/Auth/RegisterController.php on line 76

that error?

Collapse
 
naimroslan profile image
naimroslan

hi. I am new in Laravel. Have you figured out about this error?

Collapse
 
istavros profile image
Stavros Ioannidis

People... you just need to add "use App\User;" after the namespace at the top of your file.

Collapse
 
dongosiddik profile image
dongosiddik

help me
Call to undefined method App\Notifications\NewUser::via()
this is my Controllerregister.php
...
use App\Notifications\NewUser;
...
$user = User::create([
'name' => $data['name'],
'prenom' => $data['prenom'],
'matricule' => $data['matricule'],
'fonction' => $data['fonction'],
'emploi' => $data['emploi'],
// recup id
//'id_role'=> $data['role'],
'id_str'=> $id_str,
'id_direct'=> $id_direct,
'id_ser'=> $id_ser,
'email' => $data['email'],
'password' => Hash::make($data['password']),
]);

$admin = User::where('email', 'dogosidik@gmail.com')->first();
if ($admin) {
$admin->notify(new NewUser($user));
}

return $user;

}

NewUser.php

class NewUser extends Notification
{
use Queueable;

private $new_user;

/**
 * Create a new notification instance.
 *
 * @return void
 */
public function __construct(User $new_user)
{
    $this->new_user = $new_user;
}


/**
 * Get the mail representation of the notification.
 *
 * @param  mixed  $notifiable
 * @return \Illuminate\Notifications\Messages\MailMessage
 */
public function toMail($notifiable)
{
    return (new MailMessage)
        ->line('Un nouvel utilisateur a été enregistré par email' .$this->new_user->email)
        ->action('Approve user', route('admin.users', $this->new_user->id));
}

}

Collapse
 
isaacsnipe profile image
isaacsnipe

ERROR::::

Argument 1 passed to App\Notifications\NewUser::__construct() must be an instance of App\Notifications\User, instance of App\User given, called in C:\xampp\htdocs\staffPortal\app\Http\Controllers\Auth\RegisterController.php on line 75

Help please

Collapse
 
finchy70 profile image
Paul Finch

I get
Call to undefined method App\Notifications\NewUser::via()
I am using Laravel 5.8

Collapse
 
dm_254 profile image
Douglas Mandela

Hi, help please, am i missing something here ?

Collapse
 
dontito94 profile image
Francis Tito

may i help you?

Collapse
 
tanknandita profile image
tankNandita

Not any error not work this

Collapse
 
tanknandita profile image
tankNandita

in admin page not showing user that need to approve, and after register notification application not send approval button to admin email. what is missing ?

Collapse
 
andrydupti profile image
lafiolafioli

in admin page not showing user that need to approve, and after register notification application not send approval button to admin email. what is missing ?