section | title | position | slug | description |
---|---|---|---|---|
Core Concepts |
Identity Resolvers |
3 |
identity-resolvers |
Identity resolvers, as the name suggests, are responsible for resolving identities, but more specifically, the identity of a tenant. |
Identity resolvers are abstractions of the logic involved in extracting a tenants' identifier from a request.
While a lot of Sprouts functionality is built based on Laravel's auth handling,
identity resolvers do not have a corresponding component.
The closest thing, would be the entire Guard
class itself.
The primary reason behind having them abstracted in this way is that they do not rely on a particular tenancy, tenant, or even tenant provider, and can be swapped in and out without issue.
In this context, I don't mean swapping them out as in changing the primary way your application resolves tenant identities. What I mean, is that in the process of Sprout running, any identity resolver can be dropped into that place. You may be using the subdomain identity resolver as your primary resolver, but you may also have a few API endpoints that you want to wrap with the header identity resolver. Sprout lets you use as many as you like, in unison.
Identity resolvers have a simple job, they need to find a string somewhere in the current request that can be used as a tenant identifier. While that task alone is relatively straight forward, there are a number of additional bits and pieces that they should do, or be capable of doing.
Since identity resolvers make use of the request, there are most likely going to be things that they want in place when the request comes in, things that should be defined when defining routes. Forcing every developer to know all the requirements and limitations for each identity resolver wouldn't really make for nice a developer experience, so instead, the identity resolvers themselves are capable of helping with that.
public function routes(Router $router, Closure $groupRoutes, Tenancy $tenancy): RouteRegistrar;
All identity resolvers have a routes()
method that is called internally by the Route::tenanted()
helper method.
All implementations of this method should wrap the provided tenanted routes in a route group
that has all the relevant settings and options for the tenant to be resolved using it.
This will include any middleware that's relevant, as well as any possible route parameters.
Sprout itself supports three different lifecycle hooks where a tenant can be identified.
Some identity resolvers may have limitations over whether it can find an identity during a specific lifecycle hook,
or for a specific type of request.
To achieve this, each identity resolver has a canResolve()
method, which is always called before any attempts are
made.
public function canResolve(Request $request, Tenancy $tenancy, ResolutionHook $hook): bool
A primary example of where this would be best used,
is the session identity resolver
which only works during the Middleware
hook
and if the current request has a session.
The next part of the identity resolver is the bit that actually resolves the identity.
All implementations are capable of doing this given only a Request
object and a tenancy,
using the resolveFromRequest()
method.
public function resolveFromRequest(Request $request, Tenancy $tenancy): ?string;
Some identity resolvers can function when there's a current route, so they can use route parameters.
This classes also implement the Sprout\Contracts\IdentityResolverUsesParameters
interface,
and have a resolveFromRoute()
method.
public function resolveFromRoute(Route $route, Tenancy $tenancy, Request $request): ?string;
This method functions in an almost identical way, except it will use a Route
object as well as a Request
.
This contract also provides an additional method that lets you retrieve the route parameter name that it expects for a given tenancy.
public function getRouteParameterName(Tenancy $tenancy): string;
Note
Identity resolvers that make use of route parameters will also still function without a route.
The final part of an identity resolver is the setup lifecycle hook which is called during the tenancy bootstrapping,
once a tenancy has been identified.
Just like the fact that identity resolvers require routes to be set up in a specific way,
they may also require additional things to be set up in specific ways.
They can do this be handling it within the setup()
method.
public function setup(Tenancy $tenancy, ?Tenant $tenant): void;
The method is used by many of the identity resolvers, but its most common use is with ones that use route parameters. When this method is called during the tenancy bootstrapping, the identity resolver will set the default value for the tenant identifier route parameter to be the identifier for the current tenant. Without it, you'd have to now only know the name of the route parameter, but manually provide its name and value; every time you wanted to generate a tenant URL.
Sprout includes a handful of identity resolvers for just about all the different ways you may need.
The subdomain identity resolver uses the subdomain portion of the requests' host, and uses route parameters. All the subdomain identity resolver requires to function is the name of the primary domain that tenant subdomains should exist on. You can read more about this identity resolver here.
The path identity resolver uses a segment of the URLs path, and will use route parameters if present. When defining routes, this identity resolver will also set the parameter as the first segment, so if you want to be another one, you'll need to wrap the routes in a prefixed group. You can read more about this identity resolver here.
The header identity resolver uses a HTTP header present in the current request to identity the tenant. Because of limitations of Laravel, this identity resolver does not make use of route parameters. It does, however, come with a piece of middleware it adds automatically, so that a tenants' HTTP header is provided on the outgoing response too. You can read more about this identity resolver here.
The cookie identity resolver uses a cookie present in the HTTP request, expecting its contents to contain a tenant identifier. Much like with the header identity resolver, this one is also not capable of using route parameters. It will also make sure that the cookie is present on outgoing responses too. You can read more about this identity resolver here.
Warning
There are some potential side effects when using the cookie identity resolver, and the cookie service override together. This is something I plan to look into, which you can check up on here.
The session identity resolver uses a value within the session to identify the tenant. Unlike all the other identity resolvers, this one must be used during the middleware phase of the request lifecycle, to guarantee that the session has been loaded. You can read more about this identity resolver here.
Warning
This identity resolver is the most restrictive and limiting part of Sprout. Make sure to read its documentation in full so that you understand the potential side effects and incompatibilities. It is only included in the spirit of making everything available to everyone, I do not imagine it'll be used that often.
To the best of my knowledge, there's one potential identity resolver missing from this list, and it's the one that handles full domains. The domain identity resolver has been planned, and will be added post-launch. This identity resolver will internally map using subdomains, so if it's something you'd like to use, stick with subdomains for now. You can see the task for it here.
If you require an identity resolver that Sprout doesn't provide, or, you need the identity resolver to work differently, you can always build a custom one.