Laravel Customize Default Authentication

Laravel provides built-in authentication by default that includes many security features. But its built-in Authentication only works with email and password fields. If we have any status field or if we want to store logs of logged in users then we don’t have other option then building own customized authentication. In this post, we are doing login with email, password and one more extra field of status/role. I am using status field and it depends on you which field you are using on your custom authentication. 

First create a controller with artisan command like php artisan make:controller CustomAuthController This command creates a controller file on app/Http/Controllers directory of your application. Your controller class will look like this:

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class ClientAuthController extends Controller
{
    ....
}

Now we have to add AuthenticatesUsers trait that is used by Laravel’s default authentication.

namespace App\Http\Controllers;

use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;

class ClientAuthController extends Controller
{
    
    use AuthenticatesUsers;

    ....
}

Now let’s display the login form first. One more thing we have to define that our login form is only accessible by the guest, so that if the logged in member tried to access the login page after the login it will redirect to the dashboard and we will implement this on constructor method.

    use AuthenticatesUsers;


    protected $redirectTo;


    public function __construct()
    {
        $this->redirectTo = route('client.login');
        $this->middleware('guest')->except('logout');
    }

Now login form and authentication. There two built-in methods are used by AuthenticatesUsers trait, showLoginForm() with GET request and login() with POST request. In showLoginForm() you only have to return the view section. All the authentication part is handled by login() POST request. 

This login form I have implemented in my custom authentication. Please note that we are not covering the social login that you are seeing in the image. So please apologize if you get confused.

Store logs and adding an extra field for user login:

Please take a look at the below codes, I will explain these after.

 

    public function showLoginForm()
    {
        return view('login');
    }

    
    // default username is email, if you have something else then please change here
    public function username()
    {
        return 'email';
    }


    protected function validateLogin(Request $request)
    {
        $this->validate(
            $request,
            [
                'email' => 'required|email|string',
                'password' => 'required|string',
            ],
            [
                'email.required' => 'Email is required',
                'password.required' => 'Password is required',
            ]
        );
    }



    public function login(Request $request)
    {
        $this->validateLogin($request);

        // If the class is using the ThrottlesLogins trait, we can automatically throttle
        // the login attempts for this application. We'll key this by the username and
        // the IP address of the client making these requests into this application.
        if ($this->hasTooManyLoginAttempts($request)) {
            $this->fireLockoutEvent($request);

            return $this->sendLockoutResponse($request);
        }

        if ($this->attemptLogin($request)) {
            return $this->sendLoginResponse($request);
        }

        // If the login attempt was unsuccessful we will increment the number of attempts
        // to login and redirect the user back to the login form. Of course, when this
        // user surpasses their maximum number of attempts they will get locked out.
        $this->incrementLoginAttempts($request);

        return $this->sendFailedLoginResponse($request);
    }



    public function logout(Request $request)
    {
        $this->guard()->logout();

        $request->session()->invalidate();

        return redirect('/');
    }



    protected function attemptLogin( Request $request )
    {
        $credentials = array_merge( $this->credentials($request), ['status'=>1] );
      
        // If you like to store the log for the users then please implement 
        // your logic here
        
        if( $this->guard()->attempt( $credentials, $request->filled('remember') ) ) {
            return true;
        }

        return false;
    }



    protected function credentials(Request $request)
    {
        return $request->only($this->username(), 'password', 'status');
    }

As I said before that showLoginForm() and login() methods are for showing login form and handling authentication, then why these extra methods? Well all these extra methods are related to the login() method. Lets start with validateLogin() method. Its a default method that is already implemented on AuthenticatesUsers trait, but if you have more fields that you want to validate? Yes this is just to show you that you can add extra fields in the validation if you have. Now come to the credentials() method, this is also a built-in method by AuthenticatesUsers trait, that we are using to check the extra field in the database. As you see I am using status, so in my example, the user must have status 1 to get authenticated. Now the last method is attemptLogin() one more built-in method on AuthenticatesUsers trait, We are customizing it for to check the user’s status should be 1 to get login and if you want to store log for the login users then this is the method where you implement your login to store login users logs.

Here is the complete code for Laravel custom authentication

<?php

namespace App\Http\Controllers;

use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;

class CustomAuthController extends Controller
{
    
    use AuthenticatesUsers;


    protected $redirectTo;


    public function __construct()
    {
        $this->redirectTo = route('client.login');
        $this->middleware('guest')->except('logout');
    }


    public function showLoginForm()
    {
        return view('login');
    }


    public function username()
    {
        return 'email';
    }


    protected function validateLogin(Request $request)
    {
        $this->validate(
            $request,
            [
                'email' => 'required|email|string',
                'password' => 'required|string',
            ],
            [
                'email.required' => 'Email is required',
                'password.required' => 'Password is required',
            ]
        );
    }




    public function login(Request $request)
    {
        $this->validateLogin($request);

        // If the class is using the ThrottlesLogins trait, we can automatically throttle
        // the login attempts for this application. We'll key this by the username and
        // the IP address of the client making these requests into this application.
        if ($this->hasTooManyLoginAttempts($request)) {
            $this->fireLockoutEvent($request);

            return $this->sendLockoutResponse($request);
        }

        if ($this->attemptLogin($request)) {
            return $this->sendLoginResponse($request);
        }

        // If the login attempt was unsuccessful we will increment the number of attempts
        // to login and redirect the user back to the login form. Of course, when this
        // user surpasses their maximum number of attempts they will get locked out.
        $this->incrementLoginAttempts($request);

        return $this->sendFailedLoginResponse($request);
    }



    public function logout(Request $request)
    {
        $this->guard()->logout();

        $request->session()->invalidate();

        return redirect('/');
    }



    protected function attemptLogin( Request $request )
    {
        $credentials = array_merge( $this->credentials($request), ['status'=>1] );
        
        
        if( $this->guard()->attempt( $credentials, $request->filled('remember') ) ) {
            return true;
        }

        
        return false;
    }



    protected function credentials(Request $request)
    {
        return $request->only($this->username(), 'password', 'status');
    }
}