mirror of
https://github.com/archtechx/tenancy.git
synced 2026-08-06 06:34:03 +00:00
Copy the broadcaster auth state directly
Instead of re-registering the central channels on the tenant broadcaster one by one, copy the properties directly. Also the authenticated user callback wasn't copied before, so user authentication (/broadcasting/user-auth) that worked in central context would 403 in tenant context if the callback was registered in central context.
This commit is contained in:
parent
50afc49d2b
commit
fe7468ab72
1 changed files with 28 additions and 18 deletions
|
|
@ -91,27 +91,11 @@ class BroadcastingConfigBootstrapper implements TenancyBootstrapper
|
||||||
// contract gets the same tenant broadcaster that the manager uses, instead of the stale central one.
|
// contract gets the same tenant broadcaster that the manager uses, instead of the stale central one.
|
||||||
// The closure runs immediately (the extended singleton is already resolved), and it's also what makes
|
// The closure runs immediately (the extended singleton is already resolved), and it's also what makes
|
||||||
// channel auth work in tenant context -- the broadcaster resolved here gets cached as the tenant
|
// channel auth work in tenant context -- the broadcaster resolved here gets cached as the tenant
|
||||||
// manager's default driver and receives the central channel auth closures (see below).
|
// manager's default driver and receives the central broadcaster's auth state (see copyAuthState()).
|
||||||
$this->app->extend(BroadcasterContract::class, function (BroadcasterContract $centralBroadcaster) {
|
$this->app->extend(BroadcasterContract::class, function (BroadcasterContract $centralBroadcaster) {
|
||||||
$tenantBroadcaster = $this->app->make(BroadcastManager::class)->connection();
|
$tenantBroadcaster = $this->app->make(BroadcastManager::class)->connection();
|
||||||
|
|
||||||
// The newly resolved broadcaster doesn't have any channel auth closures registered, so the
|
$this->copyAuthState($centralBroadcaster, $tenantBroadcaster);
|
||||||
// closures registered in central context (e.g. in routes/channels.php) have to be passed to it
|
|
||||||
// manually, otherwise, Broadcast::auth() would throw a 403 for those channels.
|
|
||||||
// Since Laravel only ever uses the default broadcaster's channel auth closures for broadcasting auth,
|
|
||||||
// we only have to pass the channel closures to the default broadcaster.
|
|
||||||
//
|
|
||||||
// The channel() and getChannels() methods aren't part of the Broadcaster contract -- they come
|
|
||||||
// from the abstract Broadcaster class, so the closures can only be copied between broadcasters extending it
|
|
||||||
// (which all of Laravel's default broadcasters, e.g. PusherBroadcaster, do).
|
|
||||||
if ($centralBroadcaster instanceof Broadcaster && $tenantBroadcaster instanceof Broadcaster) {
|
|
||||||
// invade() because the channel options can't be retrieved through any of the broadcaster's public methods
|
|
||||||
$channelOptions = invade($centralBroadcaster)->channelOptions;
|
|
||||||
|
|
||||||
foreach ($centralBroadcaster->getChannels() as $channel => $callback) {
|
|
||||||
$tenantBroadcaster->channel($channel, $callback, $channelOptions[$channel] ?? []);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $tenantBroadcaster;
|
return $tenantBroadcaster;
|
||||||
});
|
});
|
||||||
|
|
@ -122,6 +106,32 @@ class BroadcastingConfigBootstrapper implements TenancyBootstrapper
|
||||||
Broadcast::clearResolvedInstance();
|
Broadcast::clearResolvedInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy the auth state (the channel auth closures, their options, and the authenticated user
|
||||||
|
* callback) from one broadcaster to another. A freshly resolved broadcaster has no auth state,
|
||||||
|
* so without the copying, channel auth and user auth would stop working (403) in tenant context.
|
||||||
|
*
|
||||||
|
* The auth state is stored on the abstract Broadcaster class, not in the Broadcaster
|
||||||
|
* contract, and it's stored in protected properties. Because of that, we have
|
||||||
|
* to check that both broadcasters are instances of the abstract Broadcaster class and
|
||||||
|
* use invade() to access the protected properties (for the $channels property, there
|
||||||
|
* is a public accessor -- getChannels() -- but since invade is already used here,
|
||||||
|
* we access the property directly for consistency).
|
||||||
|
*/
|
||||||
|
protected function copyAuthState(BroadcasterContract $from, BroadcasterContract $to): void
|
||||||
|
{
|
||||||
|
if (! $from instanceof Broadcaster || ! $to instanceof Broadcaster) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$fromState = invade($from);
|
||||||
|
$toState = invade($to);
|
||||||
|
|
||||||
|
$toState->channels = $fromState->channels;
|
||||||
|
$toState->channelOptions = $fromState->channelOptions;
|
||||||
|
$toState->authenticatedUserCallback = $fromState->authenticatedUserCallback;
|
||||||
|
}
|
||||||
|
|
||||||
public function revert(): void
|
public function revert(): void
|
||||||
{
|
{
|
||||||
// Revert the bound BroadcastManager and Broadcaster singletons back to their original state
|
// Revert the bound BroadcastManager and Broadcaster singletons back to their original state
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue