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:
- Preparing DB structure: migrations, models and seeders
- Restricting new users from accessing dashboard
- Notifying administrator about new user
- 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:
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.
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:
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 intoMail()
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:
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:
So here's probably the quickest way to approve new registered users in Laravel. Pretty simple, huh?
Top comments (11)
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?
hi. I am new in Laravel. Have you figured out about this error?
People... you just need to add "use App\User;" after the namespace at the top of your file.
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;
}
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
I get
Call to undefined method App\Notifications\NewUser::via()
I am using Laravel 5.8
Hi, help please, am i missing something here ?
may i help you?
Not any error not work this
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 ?
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 ?