Open norotico opened 2 years ago
Thanks, but yes my custom Bouncer models do use tenant connection.
The issue is only the User model -- when checking authorization with Bouncer::can($ability)
, Bouncer resolves the User using Laravel's auth system, which in my app is the global User (system connection) model. But the model that should be checked in this scenario is the TenantUser model (which belongs to User and is not a Laravel auth User).
My TenantUser model is properly setup, using the Authorizable
trait and doing Bouncer::useUserModel(TenantUser::class)
. But that's not enough in my use case since my TenantUser is not the auth()->user().
I set the bouncer user model on the AppServiceProvider. I'm not using a package, but DB connection is not really the issue.
When calling Bouncer::can($ability)
, Bouncer defers to the gate:
public function can($ability, $arguments = [])
{
return $this->gate()->allows($ability, $arguments);
}
Tracing this leads you to:
$this->userResolver = function ($guard = null) {
return $this->guard($guard)->user();
};
So the userResolver will always be the auth User. There's no way Bouncer would know that it needs to check abilities on the related TenantUser model without me telling Bouncer to do it, somehow. What I'm looking for is the cleanest way to do that without messing up the auth system.
For instance, this is what Bouncer/Gate would have to do in my use case after resolving the auth User:
TenantUser::whereUserId($this->userResolver()->id)->first()
As you've already discovered, this is not a question unique to Bouncer. It's a general question about Laravel's Gate
.
You can register your own Gate
in the Container
, overriding the default one:
Container::getInstance()->singleton(GateContract::class, function ($container) {
return new Gate($container, userResolver: function () use ($app) {
$user = ; // Resolve the user however you want...
return $user;
});
});
Bouncer uses whichever Gate
has been registered in the container, so if you've wired it up correctly, Bouncer will use your Gate
.
Thanks, @JosephSilber
Do I still need to Bouncer::useUserModel(...)
if I register my own Gate?
If you register your own gate before Bouncer
is instantiated, then no.
I have a multi-database multi-tenancy app where the auth User model uses the system database while the Bouncer models use the tenant databases.
Tenant DB's have a TenantUser model which belongsTo User in the system database.
By doing
Bouncer::useUserModel(TenantUser::class)
everything works fine, except for checking abilities with the Bouncer façade or directly from Laravel's gate, because there's nothing telling Bouncer or the Gate that they need to use the associated TenantUser instead of auth()->user(). I can of course do$tenantUser->can($ability)
, though.How would I go about telling Bouncer (and Laravel's Gate) to authorize the associated TenantUser instead of the global User?