Back to blog

Multi Auth in Laravel 5.4, Chapter II : Login, Logout & MiddleWares

February 03, 2017

Chapter 2 :: Login, Logout & Middleware

In our last chapter, we went through the process of creating a custom guard and registered a seller. In this chapter we will cover Login, Logout & Middleware features for our user model Seller.

TL;DR

If you are getting bored and do not have patience or will to follow the rest of chapter. Then you can refer the repository. Check the commit history for details.

Repository for Multi Auth in Laravel

Setting Expectations For Login & Logout

Lets begin this chapter by setting our expectations, which is adding routes for Login and Logout.

//web.php

//other routes

Route::post('seller_logout', 'SellerAuth\LoginController@logout');
Route::get('seller_login', 'SellerAuth\LoginController@showLoginForm');
Route::post('seller_login', 'SellerAuth\LoginController@login');

Accomplish the Expectations

Now lets create LoginController for seller

php artisan make:controller SellerAuth/LoginController

Lets work on our first route Route::post('seller_logout', 'SellerAuth\LoginController@logout');

We need to add logout() method in our LoginController. (Since we did not logged out seller in previous chapter). But unlike previous chapter, where we created all methods in our controller, we will use AuthenticatesUsers trait this time. It will keep our controller page less bloated.

//LoginController.php

namespace App\Http\Controllers\SellerAuth;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

//Class needed for login and Logout logic
use Illuminate\Foundation\Auth\AuthenticatesUsers;

class LoginController extends Controller
{
    //Trait
    use AuthenticatesUsers;
}

If we look into the properties of this trait which can be found at path vendor/laravel/framework /src/Illuminate/Foundation/ Auth/AuthenticatesUsers.php, we can observe that it includes lots of methods some of them are logout(), login(), showLoginForm(), gaurd() etc.. We will be using some these methods directly and override few of them.

NEVER EDIT ANYTHING DIRECTLY ANYTHING IN DEPENDENCY FILES( vendor folder ), IF THE LOGIC DOES NOT SUITE YOUR NEED, OVERRIDE THE LOGIC (METHOD OR OTHER PROPERTIES) IN OUR OWN CLASSES.

As you can see logout() method is already defined in the trait, so there is no need to define it again in our Controller. When we look at the first step of the logout() method we can notice that it uses guard method and calls logout() on it. The guard method of this trait returns an instance of default guard of our application, which is User guard. But we want to logout Seller not User. So we need to override guard() method in our LoginController.

//LoginController.php

namespace App\Http\Controllers\SellerAuth;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

//Class needed for login and Logout logic
use Illuminate\Foundation\Auth\AuthenticatesUsers;

//Auth facade
use Auth;

class LoginController extends Controller
{
    //Trait
    use AuthenticatesUsers;

    //Custom guard for seller
    protected function guard()
    {
      return Auth::guard('web_seller');
    }
}

We had already created Logout link in the layouts.blade.php file earlier which sends post request to seller_logout url. Now we can logout the seller by clicking on the Logout dropdown.

We are done with Logout logic, let’s move forward with implementing Login logic.

Login

Let’s work on the second route Route::get('seller_login', 'SellerAuth\LoginController @showLoginForm');

Now we need a showLoginForm() method, although its already defined in our trait, but returns login view for the User login, we want seller to view Seller login form, So let’s override this method in our LoginController.

//LoginController.php

namespace App\Http\Controllers\SellerAuth;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

//Class needed for login and Logout logic
use Illuminate\Foundation\Auth\AuthenticatesUsers;

//Auth facade
use Auth;

class LoginController extends Controller
{
    //Trait
    use AuthenticatesUsers;

    //Custom guard for seller
    protected function guard()
    {
      return Auth::guard('web_seller');
    }

    //Shows seller login form
   public function showLoginForm()
   {
       return view('seller.auth.login');
   }
}

Now let’s create the view which we defined inside showLoginForm(). Add login.blade.php at resources/views/seller/auth folder.

Login

@extends('seller.layouts')

@section('content')
<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <div class="panel panel-success">
                <div class="panel-heading">Seller Login</div>
                <div class="panel-body">
                    <form class="form-horizontal" role="form" method="POST" action="{{ url('/seller_login') }}">
                        {{ csrf_field() }}

                        <div class="form-group{{ $errors->has('email') ? ' has-error' : '' }}">
                            <label for="email" class="col-md-4 control-label">E-Mail Address</label>

                            <div class="col-md-6">
                                <input id="email" type="email" class="form-control" name="email" value="{{ old('email') }}" required autofocus>

                                @if ($errors->has('email'))
                                    <span class="help-block">
                                        <strong>{{ $errors->first('email') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>

                        <div class="form-group{{ $errors->has('password') ? ' has-error' : '' }}">
                            <label for="password" class="col-md-4 control-label">Password</label>

                            <div class="col-md-6">
                                <input id="password" type="password" class="form-control" name="password" required>

                                @if ($errors->has('password'))
                                    <span class="help-block">
                                        <strong>{{ $errors->first('password') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>

                        <div class="form-group">
                            <div class="col-md-6 col-md-offset-4">
                                <div class="checkbox">
                                    <label>
                                        <input type="checkbox" name="remember" {{ old('remember') ? 'checked' : ''}}> Remember Me
                                    </label>
                                </div>
                            </div>
                        </div>

                        <div class="form-group">
                            <div class="col-md-8 col-md-offset-4">
                                <button type="submit" class="btn btn-success">
                                    Login
                                </button>

                                <a class="btn btn-link" href="{{ url('/seller_password/reset') }}">
                                    Forgot Your Password?
                                </a>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

Let’s work on third and final route Route::post('seller_login', 'SellerAuth\LoginController@login');, where we handle data POST’ed from this form.

The login() method is already defined in AuthenticatesUsers trait. Lets summarize the steps taken by this method.

  1. It validates the login with validateLogin() method, this method checks if username and password are provided. There is no need to modify anything. Lets move to next step.
  2. It throttles the login attempt. So, there is no need for modification in this step too. (Login throttle needs its own tutorial. For now just assume that user’s IP would be blocked for a minute if he/she exceeds maximum failed login attempts). Lets move to next step.
  3. It attempts a login with seller’s username and password via attemptLogin() method. This method uses guard() method to login seller. We have already overridden the guard() method in previous steps to return an instance of our custom seller guard. So let’s move to next step.
  4. If attempt is successful then it uses sendLoginResponse() method to redirect Seller to redirectPath property. redirectPath is not yet defined in our LoginController, let’s do so.
//LoginController.php

namespace App\Http\Controllers\SellerAuth;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

//Class needed for login and Logout logic
use Illuminate\Foundation\Auth\AuthenticatesUsers;

//Auth facade
use Auth;

class LoginController extends Controller
{
    //Where to redirect seller after login.
    protected $redirectTo = '/seller_home';

    //Trait
    use AuthenticatesUsers;

    //Custom guard for seller
    protected function guard()
    {
      return Auth::guard('web_seller');
    }

    //Shows seller login form
   public function showLoginForm()
   {
       return view('seller.auth.login');
   }
}

That’s it. We are done with the Seller’s Login logic. If you have noticed, one of the good thing about using the traits is less bloated Controller Pages. (Yeah.. I know i should have used it in first chapter too)

Setting Expectations For Middleware

Middleware are just like filters for incoming requests for your application. If you are new to Middleware in Laravel, then i would suggest you to go through documentation section of laravel.

MiddleWares in Laravel

You might have noticed that we are able to access the login and registration pages for seller even after a successful login. These pages should be only be visible to people who are not logged in. We also might want to restrict guests/non-logged in sellers from accessing the seller’s homepage.

We can use laravel middleware to create this restrictions.

//web.php

//Logged in users/seller cannot access or send requests these pages
Route::group(['middleware' => 'seller_guest'], function() {

Route::get('seller_register', 'SellerAuth\RegisterController@showRegistrationForm');
Route::post('seller_register', 'SellerAuth\RegisterController@register');
Route::get('seller_login', 'SellerAuth\LoginController@showLoginForm');
Route::post('seller_login', 'SellerAuth\LoginController@login');

});

//Only logged in sellers can access or send requests to these pages
Route::group(['middleware' => 'seller_auth'], function(){

Route::post('seller_logout', 'SellerAuth\LoginController@logout');
Route::get('/seller_home', function(){
  return view('seller.home');
});

});

We have defined two middlewares, seller_guest which will restrict access of pages when seller is logged in and seller_auth which restricts access of certain pages to guests/non-logged in sellers.

Accomplish Expectations

The first step which we need to take is creating of middlewares classes, one for seller_guest and another for seller_auth.

php artisan make:middleware AuthenticateSeller
php artisan make:middleware RedirectIfSellerAuthenticated

Let’s edit our first middleware, AuthenticateSeller which can be found at app/Http/Middleware folder.

This middleware will restricting requests for guest/non-logged in sellers. Which means it will allow only logged in seller to move to the next layers of application.

//AuthenticateSeller.php

namespace App\Http\Middleware;

use Closure;

//Auth Facade
use Auth;

class AuthenticateSeller
{
   public function handle($request, Closure $next)
   {
       //If request does not comes from logged in seller
       //then he shall be redirected to Seller Login page
       if (! Auth::guard('web_seller')->check()) {
           return redirect('/seller_login');
       }

       return $next($request);
   }
}

Now let’s edit the other middleware RedirectIfSellerAuthenticated, which can be found in the same middleware folder.

This middleware will restricting requests for logged in sellers. This means it will not allow logged in seller to move to the next layers of application and will be redirected back.

//RedirectIfSellerAuthenticated.php

namespace App\Http\Middleware;

use Closure;

//Auth Facade
use Auth;

class RedirectIfSellerAuthenticated
{

  public function handle($request, Closure $next)
  {
      //If request comes from logged in user, he will
      //be redirect to home page.
      if (Auth::guard()->check()) {
          return redirect('/home');
      }

      //If request comes from logged in seller, he will
      //be redirected to seller's home page.
      if (Auth::guard('web_seller')->check()) {
          return redirect('/seller_home');
      }
      return $next($request);
  }
}

If you have noticed, we are checking if request came from logged in user or seller. We are doing this because we do not want any logged in person whether its seller or user accessing certain pages.

We added logic in middleware classes, let’s register them with the names which we have already defined in our routes. To do this, open app/Http/Kernel.php file and append our middlewares to $routeMiddleware property.

//kernel.php

protected $routeMiddleware = [
         //other Middlewares

         //add custom middlewares here as key and value pair.
         'seller_auth' => \App\Http\Middleware\AuthenticateSeller::class,
         'seller_guest' => \App\Http\Middleware\RedirectIfSellerAuthenticated::class,
     ];

End of Chapter

We are done.. Lets test out what we accomplished.

Login Page Home Page

But what happens when a seller forgets his/her password. We will cover Reseting passwords for seller in our next chapter.