Email verification on Account registration

In this article, we will cover on how to verify user’s email and activate the user account once they click on the account activation link sent in the email.

So let's start...

Step 1: Create new Model and Migration for verification

We will be creating a new table in our database which will hold the verification token that is appended in the URL and sent to the users. Let’s begin by generating the required Model and Migration file.

php artisan make:model VerifyUser -m

The make:model command will create a new Model VerifyUser in the \App directory and -m flag will create a new migration file associated with the VerifyUser model with the table name verify_users.

Now we can modify our verify_users migration file like this.

public function up()
{
    Schema::create('verify_users', function (Blueprint $table) {
        $table->integer('user_id');
        $table->string('token');
        $table->timestamps();
    });
}

Also, modify the migration file for the user's table to include a new boolean field to maintain the status of account verification.

$table->boolean('verified')->default(false);

Once that's done don't forget to migrate. run php artisan migrate

Step 2: Setup the relation between models

We can start with the User model. Add the following function to your User model.

public function verifyUser()
{
    return $this->hasOne('App\VerifyUser');
}

And also update the $fillable property. Add ['verified']

Now for the VerifyUser model

class VerifyUser extends Model
{
    protected $fillable = ['user_id', 'token'];

    public function user()
    {
        return $this->belongsTo('App\User', 'user_id');
    }
}

Step 3: Create a mailable class for sending mail

In Laravel all the emails sent by your application must be defined by a Mailable class. To generate one such class for our verify user’s email on registration. Let’s generate a class with artisan command. Run the given below command in your project root.

php artisan make:mail VerifyMail

This will create a new class under \App\Mail folder. Now edit it like this

<?php

namespace App\Mail;

use App\User;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;

class VerifyMail extends Mailable
{
    use Queueable, SerializesModels;

    public $user;

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

    /**
     * Build the message.
     *
     * @return $this
     */
    public function build()
    {
        return $this->markdown('emails.verifyUser');
    }
}

We have modified the name of view files as emails.welcome. We will create a emails folder under resources/views in which we will keep our email views. Also as you can see we have declared the $user as public and we are setting the variable in the constructor. 

Whatever variables are declared as public is by default available in the view file. Thus we can directly refer to the $user variable to get the user-related data directly in the view file.

Let’s go ahead and create the view file to send a verification email. Create a new file verifyUser.blade.php under resources/views/emails and put following contents into it.

@component('mail::message')
## Hello {{ $user['user_name'] }},

Your account has been successfully registered. Please click the below link to verify your email address. Your registered email-id is {{ $user['email'] }}.

@component('mail::button', ['url' => url('user/verify', $user->verifyUser->token)])
Verify Email
@endcomponent

Regards,<br>
{{ config('app.name') }}

<hr />

<small>
If you’re having trouble clicking the "Verify Email" button, copy and paste the URL below into your web browser:
[{{ url('user/verify', $user->verifyUser->token) }}]({{ url('user/verify', $user->verifyUser->token) }})
</small>
@endcomponent

Step 4: Sending email

Now we can modify the create function in RegisterController.php file inside App\Http\Controllers\Auth

protected function create(array $data)
{
    $user = User::create([
        'name' => $data['name'],
        'email' => $data['email'],
        'password' => bcrypt($data['password']),
    ]);

    $verifyUser = VerifyUser::create([
        'user_id' => $user->id,
        'token' => str_random(60)
    ]);

    Mail::to($user->email)->send(new VerifyMail($user));

    return $user;
}

Don't forget to import the required classes at the top of the file. i.e,

use Mail;
use App\User;
use App\VerifyUser;
use App\Mail\VerifyMail;

Step 5: Verify User Functionality

We can start by creating a new route

Route::get('/user/verify/{token}', 'Auth\RegisterController@verifyUser');

Since the functionality is related to User Registration we will create a new method verifyUser in RegisterController.php

public function verifyUser($token)
{
    $verifyUser = VerifyUser::where('token', $token)->first();
        if (isset($verifyUser)) {
            $user = $verifyUser->user;
            if (isset($user)) {
                if (!$user->verified) {
                    $verifyUser->user->verified = 1;
                    $verifyUser->user->save();
                    $status = "Your e-mail is verified. You can now login.";
                } else {
                    $status = "Your e-mail is already verified. You can now login.";
                }
            } else {
                return redirect('/login')->with('warning', "Oops! Something happend.");
            }
        } else {
            return redirect('/login')->with('warning', "Sorry your email cannot be identified.");
        }

        return redirect('/login')->with('status', $status);

}

Step 6: Restricting Un-Verified User Access

Modify LoginController.php and override the authenticated method from AuthenticatesUsers

public function authenticated(Request $request, $user)
{
    if (!$user->verified) {
        auth()->logout();
        return back()->with('warning', 'You need to confirm your account. We have sent you an activation code, please check your email.');
    }

    return redirect()->intended($this->redirectPath());
}

The authenticated method is executed just after the user is authenticated. We will override this and will use this to check if the user is activated. If not we will sign-out the user and send back to login page with a warning message.

Modify RegisterController.php and override the registered method from RegistersUsers

protected function registered(Request $request, $user)
{
    $this->guard()->logout();
    return redirect('/login')->with('status', 'We sent you an activation code. Check your email and click on the link to verify.');
}

The registered method is executed just after the user is registered into the application, we will override and modify this to sign-out the user and send him back to login with a status message.

Last we need to modify our login.blade.php file which is located under resources/views/auth. Add the following snippet to display the appropriate status messages.

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

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

Also, don't forget to support my channel by subscribing to it. Click the bell icon for not missing any of my future videos.

Comments

Popular posts from this blog

RealTime Chat Application using Laravel 5.5

RealTime Notification system using Laravel 5.5