Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a Custom Auth Guard / Provider for Laravel 5.7

Tags:

laravel

I'm migrating from Laravel 4 to 5.7 and having trouble with my custom auth provider. I've followed various walkthroughs (e.g. 1, 2, 3) as well as quite a bit of googling.

I've attempted to get this working by the following:

Set the guards and providers and link to my target model.


    'defaults' => [
        'guard' => 'custom_auth_guard',
        'passwords' => 'users',
    ],

    'guards' => [

        'custom_auth_guard' => [
            'driver' => 'session',
            'provider' => 'custom_auth_provider',
        ],
    ],

    'providers' => [

        'custom_auth_provider' => [
            'driver' => 'custom',
            'model' => App\UserAccount::class,
        ],        
    ],

Register the driver defined in the above provider. I'm piggybacking off AuthServiceProvider for ease


...
    public function boot()
    {
        $this->registerPolicies();

        \Auth::provider('custom',function() {            
        return new App\Auth\CustomUserProvider;
        });
    }
...

Created my custom provider which has my retrieveByCredentials, etc. I've replaced the logic with some die() to validate if it is making it here. In Laravel 4, it used to go to validateCredentials().


class CustomUserProvider implements UserProviderInterface {

    public function __construct()
    {
        die('__construct');
    }

    public function retrieveByID($identifier)
    {   
        die('retrieveByID');
    }

    public function retrieveByCredentials(array $credentials)
    {
        die('retrieveByCredentials');
        }

    public function validateCredentials(\Illuminate\Auth\UserInterface $user, array $credentials)
    { 
        die('validateCredentials');
        }

For reference, App/UserAccount looks like so

class UserAccount extends Authenticatable
{
    use Notifiable;

    /**
     * The database table used by the model.
     *
     * @var string
     */
    protected $table = 'public.user_account';

    // no updated_at, created_at
    public $timestamps = false;

    private $_roles = [];
    private $_permissions = [];
}

Finally, I am calling it via my controller.

        if(\Auth::attempt($credentials){
            return \Redirect::intended('/dashboard');
        }

I have also tried to call the guard direct

        if(\Auth::guard('custom_auth_guard')->attempt($credentials){
            return \Redirect::intended('/dashboard');
        }

This results in the following error: "Auth guard [custom_auth_guard] is not defined."

I've tried a few other commands to make sure there is no cache issue:

composer update
php artisan cache:clear

The results: when I call Auth::attempt($credentials) Laravel is trying to run a query on the users table. the expected result is that it would hit one of the die()'s in CustomUserProvider... or at lease try and query public.user_account as defined in the model.

I've been messing with this for some time and I must be missing something simple... hopefully someone with a bit more experience in Laravel 5 can see what I am doing wrong.

Thanks in advance!!

like image 629
Shaun Bauer Avatar asked Oct 27 '25 05:10

Shaun Bauer


1 Answers

Managed to work it out. Couple little problems but the main one was that I was trying to piggyback on AuthServiceProvider as opposed to my own provider. Below is what I did to get a custom auth provider working in Laravel 5.7

Set the provider in config.auth.php.

'providers' => [

    'user' => [
        'driver' => 'eloquent',
        'model' => \UserAccount::class,
    ],        
],

Create a new provider in app/providers/ . This links the listed provider above with the correct User Provider Code.

namespace App\Providers;

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

class CustomAuthProvider extends ServiceProvider
{

    public function register()
    {
        //
    }

    public function boot()
    {
        Auth::provider('eloquent',function()
        {
            return new CustomUserProvider(new \UserAccount());
        });
    }
}

Created my custom provider in app/auth/. This is the logic for validating the user and replaces the laravel functions for auth. I had an issue here where it was validating but not populating the user object. I originally had a test to see if the object was null and if it was, populate... however it was always populated with an empty object. removing the test allowed me to call Auth::user() functions.

namespace App\Auth;

use Illuminate\Contracts\Auth\Authenticatable as UserContract;
use Illuminate\Auth\EloquentUserProvider;

class CustomUserProvider implements EloquentUserProvider{

    public function __construct()
    {
        $this->user = $user;
    }

    public function retrieveByID($identifier)
    {   
        $this->user = \UserAccount::find($identifier);
        return $this->user;
    }

    public function retrieveByCredentials(array $credentials)
    {
       // find user by username
        $user = \UserAccount::where('name', $credentials['username'])->first();

        // validate
        return $user;
    }

    public function validateCredentials(\Illuminate\Auth\UserInterface $user, array $credentials)
    { 
        //logic to validate user
    }

Updated App/Models/UserAccount looks like so

use Illuminate\Foundation\Auth\User as Authenticatable;
class UserAccount extends Authenticatable
{
    protected $table = 'public.user_account';

    // no updated_at, created_at
    public $timestamps = false;

    private $_roles = [];
    private $_permissions = [];
}

That's it. I can now validate via the below call

        if(\Auth::attempt($credentials){
            return \Redirect::intended('/dashboard');
        }
like image 167
Shaun Bauer Avatar answered Oct 28 '25 23:10

Shaun Bauer