How to add custom provider in Laravel 5.4
I have a Laravel 5.4 application where I have to authenticate admin users with an external API that returns JSON with user information on successful login.
I create my own guard to do this:
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users'
],
'custom' => [
'driver' => 'session',
'provider' => 'customusers'
],
'api' => [
'driver' => 'token',
'provider' => 'users',
],
],
and this is my custom provider:
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
'customusers' => [
'driver' => 'jsonresponse',
'model' => App\Admin::class,
]
],
After that, I'm not sure how to proceed. I read some tutorials like from George Buckingham and created my own user provider (for now I just need to extend it to EloquentUserProvider, eventually I will override some functions to connect to the API)
<?php
namespace App\Providers;
use Illuminate\Auth\EloquentUserProvider;
use Illuminate\Support\Str;
class CustomUserProvider extends EloquentUserProvider {
}
then registered it in App \ Providers \ AuthServiceProvider
public function boot()
{
$this->registerPolicies();
Auth::provider('jsonresponse', function($app, array $config) {
return new CustomUserProvider($app['hash'], $config['model']);
});
}
and in config / app.php
'providers' => [
// Lots of other providers
// Own providers
App\Providers\CustomUserProvider::class,
],
But after that I get the following error:
Argument 1 passed to Illuminate \ Auth \ EloquentUserProvider :: __ construct () must be the Illuminate \ Contracts \ Hashing \ Hasher instance given by the Illuminate \ Foundation \ Application instance called in / var / www / public / iberorides / vendor / laravel /framework/src/Illuminate/Foundation/Application.php on line 612 and defined
If I override the constructor of my CustomUserProvider and change the parameters in the closure in the AuthServiceProvider, I get the following error:
Argument 1 passed to Illuminate \ Foundation \ Application :: bootProvider () must be the Illuminate \ Support \ ServiceProvider instance specified by the App \ Providers \ IberoUserProvider instance, which is invoked in / var / www / public / iberorides / vendor / laravel / framework /src/Illuminate/Foundation/Application.php on line 771 and defined
It makes me think that I am not doing things right.
Can anyone point me in the right direction?
Thank you so much.
source to share
The solution was simple.
First, despite what other tutorials have said, you don't need to register CustomUserProvider
with your config providers (Laravel 5.4 here). This was the reason for the errors I was getting.
I had to override two methods from EloquentUserProvider
, retrieveByCredentials(array $credentials)
where you return a model based on the provided credentials, and validateCredentials(UserContract $user, array $credentials)
where you return a boolean value based on the user's credentials.
You can use this same custom provider class with many providers, not just one, for example.
'providers' => [
'customusers' => [
'driver' => 'jsonresponse',
'model' => App\User::class,
],
'customadmins' => [
'driver' => 'jsonresponse',
'model' => App\Admin::class,
],
],
After that, when you need to check auth with any provider, you need to provide the provider as a guard, for example. Auth::guard('customusers')
...
source to share
None of the solutions I found worked for me, so I realized that this is a very simple way. ( Laravel 5.4 )
My problem was that I had to allow users to log in with their phone number.
I am overriding EloquentUserProvider
:
class PhoneUserProvider extends EloquentUserProvider
{
public function retrieveByCredentials(array $credentials)
{
if (!$credentials) {
return null;
}
// Fallback to original email authorization
if (filter_var($credentials['email'], FILTER_VALIDATE_EMAIL)) {
return parent::retrieveByCredentials($credentials);
}
// Assume we are logging in with a phone number
return UserModel::where('phone', $credentials['email'])->first();
}
}
And in my upload method, AppServiceProvider
I added the following lines:
Auth::setProvider(new PhoneUserProvider(app(Hasher::class), UserModel::class));
You can even set the provider in the login controller based on some conditions, etc.
source to share
Very small customizations to the EloquentUserProvider can be done with the following code inside the loading method of your AuthServiceProvider.
Auth::provider('eloquent', function($app, array $config)
{
return new class($app['hash'], $config['model']) extends \Illuminate\Auth\EloquentUserProvider
{
};
});
source to share