Replacing the laravel authentication with a custom authentication

Published 2 years ago by gomescleve

Replacing the laravel authentication with a custom authentication

I had built my laravel project and then had a task to replace the larevel default authentication with a custom authentication module
I could not find any post that could help me fix this issue and had to refer to many articles . There fore i decided to make a post on how this could be done So as to help any one else facing the similar issue.

  1. Files needed to be modified a) config/auth.php: Replace your eloquent driver with your custom driver
return [

/*
|--------------------------------------------------------------------------
| Default Authentication Driver
|--------------------------------------------------------------------------
|
| This option controls the authentication driver that will be utilized.
| This driver manages the retrieval and authentication of the users
| attempting to get access to protected areas of your application.
|
| Supported: "database", "eloquent"
|
*/

// 'driver' => 'eloquent', 'driver' => 'custom',

/*
|--------------------------------------------------------------------------
| Authentication Model
|--------------------------------------------------------------------------
|
| When using the "Eloquent" authentication driver, we need to know which
| Eloquent model should be used to retrieve your users. Of course, it
| is often just the "User" model but you may use whatever you like.
|
*/

'model' => 'App\User',

/*
|--------------------------------------------------------------------------
| Authentication Table
|--------------------------------------------------------------------------
|
| When using the "Database" authentication driver, we need to know which
| table should be used to retrieve your users. We have chosen a basic
| default value but you may easily change it to any table you like.
|
*/

'table' => 'user',

/*
|--------------------------------------------------------------------------
| Password Reset Settings
|--------------------------------------------------------------------------
|
| Here you may set the options for resetting passwords including the view
| that is your password reset e-mail. You can also set the name of the
| table that maintains all of the reset tokens for your application.
|
| The expire time is the number of minutes that the reset token should be
| considered valid. This security feature keeps tokens short-lived so
| they have less time to be guessed. You may change this as needed.
|
*/

'password' => [
    'email' => 'emails.password',
    'table' => 'password_resets',
    'expire' => 60,
],

];

b) config/app.php: Add your custom provider to the list of providers 'App\Providers\CustomAuthProvider',

2.Files needed to be added a. providers/CustomAuthProvider.php: Create a new Custom Provider that uses the custom driver that was defined earlier

use App\Auth\CustomUserProvider;

use Illuminate\Support\ServiceProvider;

class CustomAuthProvider extends ServiceProvider {

/**
 * Bootstrap the application services.
 *
 * @return void
 */
public function boot()
{

    $this->app['auth']->extend('custom',function()
    {

        return new CustomUserProvider();
    });
}

/**
 * Register the application services.
 *
 * @return void
 */
public function register()
{
    //
}

}

Auth/CutomerUserProvider.php :This class will replace the eloquentUserProvider and where all house keeping procedues can be initiated (after login / before logout) .

namespace App\Auth;

use App\UserPoa; use Carbon\Carbon; use Illuminate\Auth\GenericUser; use Illuminate\Contracts\Auth\Authenticatable; use Illuminate\Contracts\Auth\UserProvider;

class CustomUserProvider implements UserProvider {

/**
 * Retrieve a user by their unique identifier.
 *
 * @param  mixed $identifier
 * @return \Illuminate\Contracts\Auth\Authenticatable|null
 */
public function retrieveById($identifier)
{
    // TODO: Implement retrieveById() method.


    $qry = UserPoa::where('admin_id','=',$identifier);

    if($qry->count() >0)
    {
        $user = $qry->select('admin_id', 'username', 'first_name', 'last_name', 'email', 'password')->first();

        $attributes = array(
            'id' => $user->admin_id,
            'username' => $user->username,
            'password' => $user->password,
            'name' => $user->first_name . ' ' . $user->last_name,
        );

        return $user;
    }
    return null;
}

/**
 * Retrieve a user by by their unique identifier and "remember me" token.
 *
 * @param  mixed $identifier
 * @param  string $token
 * @return \Illuminate\Contracts\Auth\Authenticatable|null
 */
public function retrieveByToken($identifier, $token)
{
    // TODO: Implement retrieveByToken() method.
    $qry = UserPoa::where('admin_id','=',$identifier)->where('remember_token','=',$token);

    if($qry->count() >0)
    {
        $user = $qry->select('admin_id', 'username', 'first_name', 'last_name', 'email', 'password')->first();

        $attributes = array(
            'id' => $user->admin_id,
            'username' => $user->username,
            'password' => $user->password,
            'name' => $user->first_name . ' ' . $user->last_name,
        );

        return $user;
    }
    return null;



}

/**
 * Update the "remember me" token for the given user in storage.
 *
 * @param  \Illuminate\Contracts\Auth\Authenticatable $user
 * @param  string $token
 * @return void
 */
public function updateRememberToken(Authenticatable $user, $token)
{
    // TODO: Implement updateRememberToken() method.
    $user->setRememberToken($token);

    $user->save();

}

/**
 * Retrieve a user by the given credentials.
 *
 * @param  array $credentials
 * @return \Illuminate\Contracts\Auth\Authenticatable|null
 */
public function retrieveByCredentials(array $credentials)
{
    // TODO: Implement retrieveByCredentials() method.
    $qry = UserPoa::where('username','=',$credentials['username']);

    if($qry->count() >0)
    {
        $user = $qry->select('admin_id','username','first_name','last_name','email','password')->first();




        return $user;
    }
    return null;


}

/**
 * Validate a user against the given credentials.
 *
 * @param  \Illuminate\Contracts\Auth\Authenticatable $user
 * @param  array $credentials
 * @return bool
 */
public function validateCredentials(Authenticatable $user, array $credentials)
{
    // TODO: Implement validateCredentials() method.
    // we'll assume if a user was retrieved, it's good

    if($user->username == $credentials['username'] && $user->getAuthPassword() == md5($credentials['password'].\Config::get('constants.SALT')))
    {

        $user->last_login_time = Carbon::now();
        $user->save();

        return true;
    }
    return false;


}

}

UsePoa (This is my model for the admin table): This is a Model class that i created for my admin table .It implements Illuminate\Contracts\Auth\Authenticatable use Illuminate\Auth\Authenticatable; use Illuminate\Database\Eloquent\Model;

use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;

class UserPoa extends Model implements AuthenticatableContract {

use Authenticatable;
protected $table = 'admin';
protected $primaryKey  = 'admin_id';
public $timestamps = false;

}

3.Files need to know about Guard.php : This is the class that will call your User Provider depending on what is defined in the driver. Originally it use to be the EloquentUserProvider .But in this case I have replaced it with the CustomUserProvider Below is how the methods in the CustomUserProvider are called by the Guard . 1 . Login : 1. retrieveByCredentials is called to check if the user exists 2.ValidateCredentials is called to verify if the username and password are correct .Note The object that was produced in the retrieveByCredentials is sent to the ValidateCredentials and therefore no second db access is required.

  1. Authenticate a page: When ever an attempt is made to see if a user has been loged in retrieveById($identifier) is called

  2. Logout with remember me setup the method updateRememberToken(Authenticatable $user, $token) will be called

Best Answer (As Selected By gomescleve)
gomescleve

$attributes is actually not required because i am returning the full user object back . But how ever I could just return the selected attributes if required.

diego30k

How do I use this custom provider from my Controller?

jimmck
jimmck
2 years ago (67,415 XP)

Thank You!

thethan

Been looking for something similar to this. Thanks for posting it.

pmall
pmall
2 years ago (580,645 XP)

There is many $attributes arrays which are not used

sonesay

Hi,

Thank you for the write up of this implementation. I have an additional requirement to this. I need to be able to determine the submitted email + password (I'm thinking of including another field in the login form to select which DB) from two databases.

I need to be able to with the submitted fields determine which database the user belongs to and log them in accordingly. I also need to set the default database connection at this point for the rest of their login session.

Would someone please assist me in how I can achieve this?

Thanks

gomescleve

$attributes is actually not required because i am returning the full user object back . But how ever I could just return the selected attributes if required.

gomescleve

Another thing i would like to add . All the validation is handled in the Trait called AuthenticatesAndRegistersUsers which is inside the vendor directory. How ever during deployment your vendor directory may not be on your repository and your changes may not get deployed .

So the best way is to over ride certain methods that are doing the validation inside your AuthController. Since AuthController uses AuthenticatesAndRegistersUsers Trait.

But make sure to use the correct Request type.

kametepe

Hi All, say @gomescleve is it better to add custom trait for AuthenticatesAndRegistersUsers and all related traits. I would like to do authenticate with two tables, each one containing half of the credentials.

Regards

gomescleve

@kametepe if you want to make a lot of changes then you can write a new trait. But if you just want to make some changes to a few methods in that trait and use the remaining as it is . Then just over ride those methods in the class that uses this trait .

tim3011

hi @gomescleve I am using laravel 5.2 and do not have this namespace ;

namespace App\Auth;

any suggestion on where to find or to put this file

tim3011

i have been following your post but its had for me to follow this is what I understand correct me where I am going wrong please

Files needed to be modified a) config/auth.php: Replace your eloquent driver with your custom driver

This option controls the authentication driver that will be utilized. | This driver manages the retrieval and authentication of the users | attempting to get access to protected areas of your application.

return [
/*
|--------------------------------------------------------------------------
| Default Authentication Driver
|--------------------------------------------------------------------------
|
| 
|
| Supported: "database", "eloquent"
|
*/
// 'driver' => 'eloquent', 'driver' => 'custom',

/*
|--------------------------------------------------------------------------
| Authentication Model
|--------------------------------------------------------------------------
|
| When using the "Eloquent" authentication driver, we need to know which
| Eloquent model should be used to retrieve your users. Of course, it
| is often just the "User" model but you may use whatever you like.
|
*/

'model' => 'App\User',

/*
|--------------------------------------------------------------------------
| Authentication Table
|--------------------------------------------------------------------------
|
| When using the "Database" authentication driver, we need to know which
| table should be used to retrieve your users. We have chosen a basic
| default value but you may easily change it to any table you like.
|
*/

'table' => 'user',

/*
|--------------------------------------------------------------------------
| Password Reset Settings
|--------------------------------------------------------------------------
|
| Here you may set the options for resetting passwords including the view
| that is your password reset e-mail. You can also set the name of the
| table that maintains all of the reset tokens for your application.
|
| The expire time is the number of minutes that the reset token should be
| considered valid. This security feature keeps tokens short-lived so
| they have less time to be guessed. You may change this as needed.
|
*/

'password' => [
    'email' => 'emails.password',
    'table' => 'password_resets',
    'expire' => 60,
],
];

b) config/app.php: Add your custom provider to the list of providers

 'App\Providers\CustomAuthProvider',

2.Files needed to be added.Create a new Custom Provider that uses the custom driver that was defined earlier

app\ providers/CustomAuthProvider.php: 

The class customAuthProvider :This class will replace the eloquentUserProvider and where all house keeping procedues can be initiated (after login / before logout) .

use App\Auth\CustomUserProvider;
use Illuminate\Support\ServiceProvider;

class CustomAuthProvider extends ServiceProvider {

/**
 * Bootstrap the application services.
 *
 * @return void
 */
public function boot()
{

    $this->app['auth']->extend('custom',function()
    {

        return new CustomUserProvider();
    });
}

/**
 * Register the application services.
 *
 * @return void
 */
public function register()
{
    //
}
}

Auth/CustomerUserProvider.php

namespace App\Auth;
use App\UserPoa
 use Carbon\Carbon; 
use Illuminate\Auth\GenericUser; 
use Illuminate\Contracts\Auth\Authenticatable;
 use Illuminate\Contracts\Auth\UserProvider;

class CustomUserProvider implements UserProvider {

/**
 * Retrieve a user by their unique identifier.
 *
 * @param  mixed $identifier
 * @return \Illuminate\Contracts\Auth\Authenticatable|null
 */
public function retrieveById($identifier)
{
    // TODO: Implement retrieveById() method.


    $qry = UserPoa::where('admin_id','=',$identifier);

    if($qry->count() >0)
    {
        $user = $qry->select('admin_id', 'username', 'first_name', 'last_name', 'email', 'password')->first();

        $attributes = array(
            'id' => $user->admin_id,
            'username' => $user->username,
            'password' => $user->password,
            'name' => $user->first_name . ' ' . $user->last_name,
        );

        return $user;
    }
    return null;
}

/**
 * Retrieve a user by by their unique identifier and "remember me" token.
 *
 * @param  mixed $identifier
 * @param  string $token
 * @return \Illuminate\Contracts\Auth\Authenticatable|null
 */
public function retrieveByToken($identifier, $token)
{
    // TODO: Implement retrieveByToken() method.
    $qry = UserPoa::where('admin_id','=',$identifier)->where('remember_token','=',$token);

    if($qry->count() >0)
    {
        $user = $qry->select('admin_id', 'username', 'first_name', 'last_name', 'email', 'password')->first();

        $attributes = array(
            'id' => $user->admin_id,
            'username' => $user->username,
            'password' => $user->password,
            'name' => $user->first_name . ' ' . $user->last_name,
        );

        return $user;
    }
    return null;



}

/**
 * Update the "remember me" token for the given user in storage.
 *
 * @param  \Illuminate\Contracts\Auth\Authenticatable $user
 * @param  string $token
 * @return void
 */
public function updateRememberToken(Authenticatable $user, $token)
{
    // TODO: Implement updateRememberToken() method.
    $user->setRememberToken($token);

    $user->save();

}

/**
 * Retrieve a user by the given credentials.
 *
 * @param  array $credentials
 * @return \Illuminate\Contracts\Auth\Authenticatable|null
 */
public function retrieveByCredentials(array $credentials)
{
    // TODO: Implement retrieveByCredentials() method.
    $qry = UserPoa::where('username','=',$credentials['username']);

    if($qry->count() >0)
    {
        $user = $qry->select('admin_id','username','first_name','last_name','email','password')->first();




        return $user;
    }
    return null;


}

/**
 * Validate a user against the given credentials.
 *
 * @param  \Illuminate\Contracts\Auth\Authenticatable $user
 * @param  array $credentials
 * @return bool
 */
public function validateCredentials(Authenticatable $user, array $credentials)
{
    // TODO: Implement validateCredentials() method.
    // we'll assume if a user was retrieved, it's good

    if($user->username == $credentials['username'] && $user->getAuthPassword() == md5($credentials['password'].\Config::get('constants.SALT')))
    {

        $user->last_login_time = Carbon::now();
        $user->save();

        return true;
    }
    return false;


}
}

UserPoa (This is my model for the admin table): This is a Model class that i created for my admin table .It implements Illuminate\Contracts\Auth\Authenticatable

use Illuminate\Auth\Authenticatable;
 use Illuminate\Database\Eloquent\Model;

use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;

class UserPoa extends Model implements AuthenticatableContract {

use Authenticatable;
protected $table = 'admin';
protected $primaryKey  = 'admin_id';
public $timestamps = false;
}

3.Files need to know about Guard.php : This is the class that will call your User Provider depending on what is defined in the driver. Originally it use to be the EloquentUserProvider .But in this case I have replaced it with the CustomUserProvider Below is how the methods in the CustomUserProvider are called by the Guard . 1 . Login :

  1. retrieveByCredentials is called to check if the user exists 2.ValidateCredentials is called to verify if the username and password are correct .

Note The object that was produced in the retrieveByCredentials is sent to the ValidateCredentials and therefore no second db access is required.

Authenticate a page: When ever an attempt is made to see if a user has been loged in retrieveById($identifier) is called Logout with remember me setup the method updateRememberToken(Authenticatable $user, $token) will be called

done all this the way I have put it down but still get errors like

InvalidArgumentException in CreatesUserProviders.php line 40:
Authentication user provider [custom] is not defined.

please advise where am i going wrong

poupouxios

For anyone having problems to set it up, below is the changes I've made for Laravel 5.3:

  • config/auth.php : Called it externalauthapi my custom driver
<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Authentication Defaults
    |--------------------------------------------------------------------------
    |
    | This option controls the default authentication "guard" and password
    | reset options for your application. You may change these defaults
    | as required, but they're a perfect start for most applications.
    |
    */

    'defaults' => [
        'guard' => 'api',
        'passwords' => '',
    ],

    /*
    |--------------------------------------------------------------------------
    | Authentication Guards
    |--------------------------------------------------------------------------
    |
    | Next, you may define every authentication guard for your application.
    | Of course, a great default configuration has been defined for you
    | here which uses session storage and the Eloquent user provider.
    |
    | All authentication drivers have a user provider. This defines how the
    | users are actually retrieved out of your database or other storage
    | mechanisms used by this application to persist your user's data.
    |
    | Supported: "session", "token"
    |
    */

    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],

        'api' => [
            'driver' => 'session',
            'provider' => 'api_users',
        ],
    ],

    /*
    |--------------------------------------------------------------------------
    | User Providers
    |--------------------------------------------------------------------------
    |
    | All authentication drivers have a user provider. This defines how the
    | users are actually retrieved out of your database or other storage
    | mechanisms used by this application to persist your user's data.
    |
    | If you have multiple user tables or models you may configure multiple
    | sources which represent each model / table. These sources may then
    | be assigned to any extra authentication guards you have defined.
    |
    | Supported: "database", "eloquent"
    |
    */

    'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => App\Model\Staff::class,
        ],
        'api_users' => [
            'driver' => 'externalauthapi',
            'model' => App\Model\Staff::class,
        ],
    ],

    /*
    |--------------------------------------------------------------------------
    | Resetting Passwords
    |--------------------------------------------------------------------------
    |
    | You may specify multiple password reset configurations if you have more
    | than one user table or model in the application and you want to have
    | separate password reset settings based on the specific user types.
    |
    | The expire time is the number of minutes that the reset token should be
    | considered valid. This security feature keeps tokens short-lived so
    | they have less time to be guessed. You may change this as needed.
    |
    */

    'passwords' => [
        'users' => [
            'provider' => 'users',
            'table' => 'password_resets',
            'expire' => 60,
        ],
    ],

];
  • config/app.php:

Add the below line in providers array:

App\Providers\ExternalAuthApiServiceProvider::class
  • Create your custom provider. In my case is called ExternalAuthApiServiceProvider and it looks like below:
<?php

namespace App\Providers;

use App\Auth\ExternalAuthApiUserProvider;
use Illuminate\Support\ServiceProvider;

class ExternalAuthApiServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap the application services.
     *
     * @return void
     */
    public function boot()
    {
        $this->app['auth']->provider('externalauthapi',function()
        {
            return new ExternalAuthApiUserProvider();
        });
    }

    /**
     * Register the application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

  • As you see on the above custom provider, a custom User provider is created which will handle all the different ways to authenticate the user. Create a UserProvider - in my case is called ExternalAuthApiUserProvider.php - and add it under App\Auth folder. If Auth folder doesn't exist, create one under the app folder.

The rest are the same depending of how you want to authenticate the user. In my case, I use an API to generate a token and authenticate the user and my current application doesn't have any database to retrieve the user.

pvrs2006@gmail.com

Hi Folks,

Thanks for your detailed steps. I'm quiet knew to laravel 5.3 and trying to customize the authentication.

The requirement is need to check the user account (check with only user login id and no password) is exist in the database then need to check the user is exist in the another server using api.

I followed the above mentioned custom config but getting below errors "FatalThrowableError in EloquentUserProvider.php line 114: Type error: Argument 1 passed to Illuminate\Auth\EloquentUserProvider::validateCredentials() must be an instance of Illuminate\Contracts\Auth\Authenticatable, instance of".

Please assist

Please sign in or create an account to participate in this conversation.