Spize Tech

The blog help to build your skill.

Data Structure and algorithm

Questions and Answers

More


In the previous tutorial, we talked about Database Migrations, Config, and Todos CRUD with Eloquent Models. This tutorial is all about Authentication. We will create a full Authentication System with Email Verification and Password Reset.

Authentication

Laravel comes with a complete authentication system right out of the box, where users can register/login, reset their passwords , etc. There are some things to consider when implementing authentication with laravel. Laravel includes a User model which will be used for default authentication driver for users. We already have all the controllers in app/Http/Controllers/Auth and laravel also includes migrations for users and password_resets table. To implement auth all we have to do is run make:auth command. It will create all the views in resources/views directory and add routes in our web.php routes file.

php artisan make:auth

It will ask to replace the current layout, just press enter and it will keep our old layout. Let’s update our navbar.blade.php to add login/register and logout links:
<!-- Right Side Of Navbar -->
<ul class="navbar-nav ml-auto">
    @auth
        <li class="nav-item">
            <a href="{{route('todos.index')}}" class="nav-link">Todos</a>
        </li>
        <li class="nav-item">
            <a href="{{route('todos.create')}}" class="nav-link">New Todo</a>
        </li>
        <li class="nav-item dropdown">
            <a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" v-pre>
                {{ Auth::user()->name }} <span class="caret"></span>
            </a>
            <div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdown">
                <a class="dropdown-item" href="{{route('home')}}">
                    Dashboard
                </a>
                <a class="dropdown-item" href="#" onclick="event.preventDefault();document.getElementById('logout-form').submit();">
                    Logout
                </a>
                <form id="logout-form" action="{{ route('logout') }}" method="POST" style="display: none;">
                    @csrf
                </form>
            </div>
        </li>
    @else
        <li class="nav-item">
            <a href="{{route('login')}}" class="nav-link">Login</a>
        </li>
        <li class="nav-item">
            <a href="{{route('register')}}" class="nav-link">Register</a>
        </li>
    @endauth
</ul>
    auth_links_right_navbar.blade.php

@auth is used to check if a user is authenticated. Inside the @auth, we have todos and create todos as well as a dropdown that has dashboard link and a logout link. Logout link is submitting a hidden form because logout uses POST method. Inside the @else we have login and register links. Laravel also has a @guest directive which is opposite to @auth:
@guest
  {{-- Stuff for guest/unauthenticated users --}}
@endguest
    @guest.blade.php

You can also use it with @else directive:
@guest
  {{-- Stuff for guest/unauthenticated users --}}
@else
  {{-- Stuff for authenticated users --}}
@endguest
    @guest_else.blade.php

You can access the current authenticated user object with Auth::user():
{{ Auth::user()->name }} {{-- <- Email of the user --}}
{{ Auth::user()->id }} {{-- <- id of the user --}}
{{-- Laravel also has shorthand method for id --}}
{{ Auth::id() }} {{-- <- shorthand for id --}}
    auth_user.blade.php

Authentication 

Routes First let’s take a look at web.php routes file, you will see that now we have two new lines of code:
<?php
Auth::routes();
Route::get('/home', 'HomeController@index')->name('home');
    default_auth_routes.php

Auth::routes() will register all the routes related to authentication like login, register and password reset. Second route is the “home” route that will redirect the user to home view/dashboard after login.You can type the route:list command to see all routes registered by your application. For the sake of learning, I’m putting all the routes here so you guys can understand better:

<?php
/**
 * Login Route(s)
 */
Route::get('login', 'Auth\LoginController@showLoginForm')->name('login');
Route::post('login', 'Auth\LoginController@login');
Route::post('logout', 'Auth\LoginController@logout')->name('logout');
/**
 * Register Route(s)
 */
Route::get('register', 'Auth\RegisterController@showRegistrationForm')->name('register');
Route::post('register', 'Auth\RegisterController@register');
/**
 * Password Reset Route(S)
 */
Route::get('password/reset', 'Auth\ForgotPasswordController@showLinkRequestForm')->name('password.request');
Route::post('password/email', 'Auth\ForgotPasswordController@sendResetLinkEmail')->name('password.email');
Route::get('password/reset/{token}', 'Auth\ResetPasswordController@showResetForm')->name('password.reset');
Route::post('password/reset', 'Auth\ResetPasswordController@reset')->name('password.update');
/**
 * Email Verification Route(s)
 */
Route::get('email/verify', 'Auth\VerificationController@show')->name('verification.notice');
Route::get('email/verify/{id}', 'Auth\VerificationController@verify')->name('verification.verify');
Route::get('email/resend', 'Auth\VerificationController@resend')->name('verification.resend');
    actual_auth_routes.php

Again, you don’t need to put all the routes in your code (because we don’t want duplicate routes). It’s just to show you the actual routes responsible for authentication.

Authentication Controllers

Let’s take a look at our controllers, located in app/Http/Controllers/Auth directory. There are total 5 controllers:
  • ForgotPasswordController sends the password reset email to a specified user.
  • LoginController logs in and out a specific user.
  • RegisterController registers a user.
  • ResetPasswordController resets the password of a user.
  • VerficationController sends a verification email to the user and verifies a user.
All the these controllers except ForgotPasswordController have a protected property $redirectTo which is used to specify the redirect url when they log in or register. By default, they have /home route but you can specify a different url if you want. If you open the LoginController, you will see a __contruct() method nothing else and that’s because all authentication controllers use Traits that have all the functionality. These Traits can be found in vendor/laravel/framework/src/Illuminate/Foundation/Auth directory and if you want to modify a certain method then override them in the controllers. Laravel also comes with login throttling and a user will not be able to login till 60 seconds if 5 tries have failed.

Don’t modify those traits since they are just dependencies and will change when you reinstall them.

Authentication Views

All the authentication views can be found in resources/views/auth directory. These views are using bootstrap styling but you can change them however you like. All we are doing in these authentication views is submitting a form and we have already learned it in the previous tutorial so I’m not going to explain them here. Since we have created the users and password_resets table when we had created the todos table so all we have to do is click register link and create a new user. Register button will automatically log us in and redirect to home view.

Middleware

A Middleware is used for filtering http requests made to your application. For example, you don’t want to allow guests to see the home (dashboard) of your application and same goes for authenticated users, they don’t need to see the login and register views. Laravel already comes with middleware like “auth” which will block all the unauthenticated request entering your application and “guest” middleware will block all the requests from authenticated users. You can also create your own middleware which we won’t do in this series. You can apply middleware directly in your controllers or in your routes. To define a middleware in a controller you can use $this->middleware() inside a constructor. Add below code to your TodosController:
<?php
public function __construct(){
    $this->middleware('auth');
}
    constructor_middleware.php

This will block access to all the methods from unauthenticated users. If you want to ignore certain methods then you can chain middleware() method with except() which takes an array of strings (you can also pass an array of strings to middleware() method if you have more than one middleware). For example in our LoginController we have “guest” middleware except for logout() method:
<?php
public function __construct(){
    $this->middleware('guest')->except('logout');
}
    constructor_middleware_with_except.php

To apply a middleware to a route we can use middleware() method:
<?php
Route::get('/home','HomeController@index')->name('home')->middleware('auth'); //just an example
    middleware_route.php           

Manually Authenticating Users

 There may be some cases where you want create authentication yourself like a seperate admin authentication. Laravel provides a few methods that can be used for authentication so let’s look at them:

 Using attempt() method which receives an associative array of email and password and the second parameter is a boolean for remember me cookie which will keep the users logged in even after closing the browser:
<?php
Auth::attempt([ 'email' => $request->email , 'password' => $request->password ], $request->remember);
    auth_login_with_attempt.php

Using a User instance or Id field:
<?php
Auth::login($user);
Auth::login($user,true); //remember the user.
Auth::loginUsingId(1); //login user by id column.
        login_methods_laravel.php

Logout the user:
<?php
Auth::logout();
    logout_laravel.php

Login example:
<?php
use Auth; //class import
public function login(Request $request)
{
  //validate the fields....
  
  $credentials = [ 'email' => $request->email , 'password' => $password ];
  
  if(Auth::attempt($crendentials,$request->remember)){ // login attempt
    //login successful, redirect the user to your preferred url/route...
  }
  
  //login failed...
}
    login_method_ex.php

When you register users, you will have to hash the password before storing it to the database and for that you can use Hash facade:

<?php
//class imports....
use Auth;
use Hash;
public function register(Request $request)
{
  //validate the fields...
  
  $password = Hash::make($request->password);
  
  $user = new User;
  $user->name = $request->name;
  $user->email = $request->email;
  $user->password = $password; //hashed password.
  $user->save();
  
  //login as well.
  Auth::login($user,true);
  
  //redirect to your preferred url/route....
}
    auth_register_ex.php

Laravel uses guards for authentication which gives you the ability to manage multiple authentications from multiple tables like a separate admins table and users table. We won’t talk about guards in this series but if curious then feel free to explore auth.php config file and documentation.

Email Verification

 Before Laravel 5.7, you would have to implement email verification by yourself or use a package but now email verification is provided by laravel itself. To implement email verification your User model must implement “MustVerifyEmail” contract. All you have to do is add the “Implements MustVerifyEmail” to the class declaration:

<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail; // <- important
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable implements MustVerifyEmail // <- update this line
{
  //your model code
}
    verify_email_user_model.php

Let’s setup our mail driver. We will use mailtrap which works like a sandbox and instead of sending the emails to specified users, it will capture all the emails in the mailtrap inbox. First signup with mailtrap and login then click “Demo Inboxes” and you will see the credentials:


Put your “username”, “password” and set MAIL_ENCRYPTION to “tls” and restart the dev server.
MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=your_mailtrap_username
MAIL_PASSWORD=your_mailtrap_password
MAIL_ENCRYPTION=tls
    mailtrap_credentials.env

Last thing we need to do is add the verify middleware to the auth routes:
<?php
//This will enable email verification routes
Auth::routes(['verify' => true]);
    default_auth_routes_email_verify.php

To protect routes from unverified users, we can use “verified” middleware. In this tutorial, we will add the “verified” middleware to the “home” route:
<?php
Route::get('/home', 'HomeController@index')->name('home')->middleware('verified');
    verified_middleware_route.php

You can also use it in your controllers:
<?php
public function __construct(){
  $this->middleware(['auth','verified']);
}
    verified_middleware_constructor.php

This will block access to unverified users and only allow users that have verified their email. Now when you register a new user, it will send a verification email to that user (in our mailtrap inbox) and redirect us to verify view (same will happen when a old user tries to access home route):

 Go to your mailtrap inbox, open the email and click “Verify Email Address” button, it will open up our application and now we can access the home route.
 if the url in email is localhost then you should change APP_URL to “http://127.0.0.1:8000" and restart the server.

Resetting User’s Password 

Since we have already setup the mail driver, now all we have to do is click “Forgot Your Password” button on the login form and it will open the password email view. Enter your email, click “Send Password Reset” Link button and it will send the password reset email to your mailtrap inbox. Now open the email from mailtrap and click “Reset Password” button. This will open the password reset form where you can reset the password. 

Next tutorial is the last and will be about eloquent relationships and image upload. You will learn One to Many and One to Many (Inverse) relationships and some useful methods for eloquent models. We will create a foreign key constraint so a user can only modify/create his/her own todos and won’t be able to see todos from other users and lastly we will upload the user profile image.

Feel free to comment below.  Let’s continue to the next tutorial:

Here is the previous tutorial

To get Source Code Click here

No comments:

Post a Comment