This is a short "how-to implement" of a tenant scopeing for sessions when using
- Laravel 8 (laravel.com)
- Laravel Jetstream (https://jetstream.laravel.com)
- spatie/laravel-multitenancy package (https://spatie.be/docs/laravel-multitenancy)
with a multi-database setup and sessions within the landlord database.
Disclamer: No warranty or guarantee of completeness and correctness. This is a record for personal use and should be considered as a "personal note".
A multi-tenant app with multi-database setup is planned. Each tenant has its own database. (tenant databases). Just as described in the basic setup of spatie/laravel-multitenancy: https://spatie.be/docs/laravel-multitenancy/v2/installation/base-installation.
By default all tenant sessions are stored in the main database (landlord).
To avoid conflicts / security issues between different tenant sessions,
Laravel's DatabaseSessionHandler
will be extended to scope the sessions by a tenant_id.
Because this sample uses Laravel Jetstream, we'll override the LogoutOtherBrowserSessionsForm
Livewire component to handle the new situation.
-
- Migration
-
- CustomSessionHandler
-
- SessionServiceProvider
-
- SESSION_DRIVER environment variable
-
- Jetstream - LogoutOtherBrowserSessionsForm
We need to add a new tenant_id
column to laravels default sessions
table. ($table->unsignedBigInteger('tenant_id')->nullable()->index();
)
and migrate the new sessions table.
We need to create a custom SessionHandler. Because we want to use allmost all features of Laravel's default DatabaseSessionHandler
,
we'll extend this and overwrite the necessary methods. Save the file at any location you prefer, (there is no specific folder provided to save your personal SessionHandlers)
within this example, we'll save it at app\SessionHandlers\CustomSessionHandler.php
(Content: You find the file within this gist.)
The lines changed in comparison with the original methods are provided with comments.
To load the CustomSessionHandler, we'll need to register it, we'll do this within a dedicated ServiceProvider
(it's fine to do this within an already existing provider, but i like to separate it ;-)) called SessionServiceProvider
and save it as app\Providers\SessionServiceProvider.php
(Content: You find the file within this gist.)
The handler will be loaded with the same properties like the original DatabaseSessionHandler would be.
To register the newly crated SessionServiceProvider
, append it to the config array providers
within the file config/app.php
.
To use the new driver, just add / update the following line within your .env file: SESSION_DRIVER=custom-database
.
Jetstream provides a great feature which allows the user to logout from other sessions. We need to tweak this feature a litte bit in order to respect our previous changes.
-
Within the
resources/views/profile/show.blade.php
:- Change the line
@livewire('profile.logout-other-browser-sessions-form')
to@livewire('logout-other-browser-sessions-form')
- Change the line
-
Create a new livewire component:
php artisan make:livewire LogoutOtherBrowserSessionsForm
-
Do not edit the blade view, just leave it blank, the component will use the view of the extended component.
-
Edit the new
app\Http\Livewire\LogoutOtherBrowserSessionsForm.php
and let it extend\Laravel\Jetstream\Http\Livewire\LogoutOtherBrowserSessionsForm
, then override the the methodsdeleteOtherSessionRecords
andgetSessionsProperty
. (Content: You find the file within this gist.) The lines changed in comparison with the original methods are provided with comments.
Note: Software = Content of this gist.
Copyright 2021 Frederic Habich [email protected]
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
I have a suggestion like so:
Seems more readable, but I haven't tested it.
Thanks for sharing your code with us.