loading...
Cover image for Laravel: Approve New Registered Users from Administrator

Laravel: Approve New Registered Users from Administrator

povilaskorop profile image Povilas Korop ・6 min read

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

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

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

php artisan make:auth

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

And then the migration itself:

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

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

protected $fillable = [
    'name', 'email', 'password', 'admin', 'approved_at'
];

Seeding admin user

This command will help us:

php artisan make:seeder AdminSeeder

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(),
        ]);
    }
}

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

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

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

php artisan migrate --seed

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

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');
}

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');
});

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

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);
    }
}

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,
];

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');
    });
});

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

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));
    }

}

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;
}

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

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

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);
    }
}

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,
];

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');
    });
});

Last thing we need is to implement the actual approval.

php artisan make:controller UserController

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');
    }

}

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

Final visual result:

Laravel administrator approve users

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

Posted on Oct 22 '18 by:

povilaskorop profile

Povilas Korop

@povilaskorop

Laravel developer, with total 15 years of PHP experience. Founder of QuickAdminPanel.com - admin generator for Laravel.

Discussion

markdown guide
 

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?

 

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

 

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));
}

}

 
 

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 ?

 

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