We can't find the internet
Attempting to reconnect
Something went wrong!
Hang in there while we get back on track
Imagine you have a Laravel web application with different types of users. Let's you can have both internal
as well as
external
users. Let's also assume that for logging, depending on which
guard is used, you want to either allow only
internal or exteral users to login. There might be places where you want to allow both.
Shouldn't be hard, except if you happen to have a global scope
that filters out all external users. So when you try to login as an external user, you get a ModelNotFoundException
because the global scope filters out all external users.
Let's first take a look at how the global scope was configured.
In my apps, I prefer to define them as a class and then add them to the model in the booted
method. This way, I can
easily reuse them or find them.
app/Scopes/OnlyInternalUsersScope.php
<?php
namespace App\Scopes;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;
final class OnlyInternalUsersScope implements Scope
{
public function apply(Builder $builder, Model $model): void
{
$builder->where('type', 'internal');
}
}
app/Models/User.php
<?php
namespace App\Models;
use App\Scopes\OnlyInternalUsersScope;
final class User extends Authenticatable
{
protected static function booted(): void
{
self::addGlobalScope(new OnlyInternalUsersScope());
}
}
At this point, whenever you try to find a user, it will only return users with the type internal
.
To configure the authentication, we need to take some extra steps. The first thing I did is to create a class that
extends EloquentUserProvider
.
It's implementation is pretty simple. It just overrides the
retrieveById
method and
removes the global scope. Doing so will enable it to search for all users, regardless of their type.
app/Providers/AllUsersProvider.php
<?php
namespace App\Providers;
use App\Scopes\OnlyInternalUsersScope;
use Illuminate\Auth\EloquentUserProvider;
class AllUsersProvider extends EloquentUserProvider
{
public function retrieveById($identifier)
{
return $this->createModel()
->newQuery()
->withoutGlobalScope(OnlyInternalUsersScope::class)
->find($identifier);
}
}
The next step is to add a new auth provider to the AuthServiceProvider
. In my scenario, I called it external
and
uses the provider which we just created.
app/Providers/AuthServiceProvider.php
<?php
namespace App\Providers;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Auth;
class AuthServiceProvider extends ServiceProvider
{
public function boot()
{
Auth::provider('all-users', function ($app, $config) {
return new AllUsersProvider($app['hash'], $config['model']);
});
}
}
The final step is to configure the auth guards and providers. In the example below, I've added the external
guard and
a provider called "all-users". The web
guard is the default one and is used for internal users. The all-users
guard
is used for external and internal users and uses the driver we have just defined.
config/auth.php
<?php
return [
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'internal-users',
],
'all-users' => [
'driver' => 'session',
'provider' => 'all-users',
],
],
'providers' => [
'internal-users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
'all-users' => [
'driver' => 'all-users',
'model' => App\User::class,
],
],
];
If this post was enjoyable or useful for you, please share it! If you have comments, questions, or feedback, you can email my personal email. To get new posts, subscribe use the RSS feed.