mirror of
https://github.com/archtechx/tenancy.git
synced 2025-12-12 18:44:03 +00:00
Combined subdomain/domain identification
This commit is contained in:
parent
8ea4940f34
commit
f328fc9c08
4 changed files with 141 additions and 4 deletions
32
src/Middleware/InitializeTenancyByDomainOrSubdomain.php
Normal file
32
src/Middleware/InitializeTenancyByDomainOrSubdomain.php
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Stancl\Tenancy\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class InitializeTenancyByDomainOrSubdomain
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
if ($this->isSubdomain($request->getHost())) {
|
||||
return app(InitializeTenancyBySubdomain::class)->handle($request, $next);
|
||||
} else {
|
||||
return app(InitializeTenancyByDomain::class)->handle($request, $next);
|
||||
}
|
||||
}
|
||||
|
||||
protected function isSubdomain(string $hostname): bool
|
||||
{
|
||||
return Str::endsWith($hostname, config('tenancy.central_domains'));
|
||||
}
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ namespace Stancl\Tenancy\Middleware;
|
|||
use Closure;
|
||||
use Illuminate\Http\Response;
|
||||
use Stancl\Tenancy\Exceptions\NotASubdomainException;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class InitializeTenancyBySubdomain extends InitializeTenancyByDomain
|
||||
{
|
||||
|
|
@ -51,7 +52,10 @@ class InitializeTenancyBySubdomain extends InitializeTenancyByDomain
|
|||
$parts = explode('.', $hostname);
|
||||
|
||||
// If we're on localhost or an IP address, then we're not visiting a subdomain.
|
||||
if (in_array(count($parts), [1, 4])) {
|
||||
$notADomain = in_array(count($parts), [1, 4]);
|
||||
$thirdPartyDomain = ! Str::endsWith($hostname, config('tenancy.central_domains'));;
|
||||
|
||||
if ($notADomain || $thirdPartyDomain) {
|
||||
$handle = static::$onInvalidSubdomain ?? function ($e) {
|
||||
throw $e;
|
||||
};
|
||||
|
|
@ -59,9 +63,6 @@ class InitializeTenancyBySubdomain extends InitializeTenancyByDomain
|
|||
return $handle(new NotASubdomainException($hostname));
|
||||
}
|
||||
|
||||
// todo should we verify that the subdomain belongs to one of our central domains?
|
||||
// if yes, then write a test for it.
|
||||
|
||||
return $parts[static::$subdomainIndex];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
78
tests/v3/CombinedDomainAndSubdomainIdentificationTest.php
Normal file
78
tests/v3/CombinedDomainAndSubdomainIdentificationTest.php
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
<?php
|
||||
|
||||
namespace Stancl\Tenancy\Tests\v3;
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Stancl\Tenancy\Database\Models;
|
||||
use Stancl\Tenancy\Database\Models\Concerns\HasDomains;
|
||||
use Stancl\Tenancy\Middleware\InitializeTenancyByDomainOrSubdomain;
|
||||
use Stancl\Tenancy\Tests\TestCase;
|
||||
|
||||
class CombinedDomainAndSubdomainIdentificationTest extends TestCase
|
||||
{
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
Route::group([
|
||||
'middleware' => InitializeTenancyByDomainOrSubdomain::class,
|
||||
], function () {
|
||||
Route::get('/foo/{a}/{b}', function ($a, $b) {
|
||||
return "$a + $b";
|
||||
});
|
||||
});
|
||||
|
||||
config(['tenancy.tenant_model' => Tenant::class]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function tenant_can_be_identified_by_subdomain()
|
||||
{
|
||||
config(['tenancy.central_domains' => ['localhost']]);
|
||||
|
||||
$tenant = Tenant::create([
|
||||
'id' => 'acme',
|
||||
]);
|
||||
|
||||
$tenant->domains()->create([
|
||||
'domain' => 'foo',
|
||||
]);
|
||||
|
||||
$this->assertFalse(tenancy()->initialized);
|
||||
|
||||
$this
|
||||
->get('http://foo.localhost/foo/abc/xyz')
|
||||
->assertSee('abc + xyz');
|
||||
|
||||
$this->assertTrue(tenancy()->initialized);
|
||||
$this->assertSame('acme', tenant('id'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function tenant_can_be_identified_by_domain()
|
||||
{
|
||||
config(['tenancy.central_domains' => []]);
|
||||
|
||||
$tenant = Tenant::create([
|
||||
'id' => 'acme',
|
||||
]);
|
||||
|
||||
$tenant->domains()->create([
|
||||
'domain' => 'foobar.localhost',
|
||||
]);
|
||||
|
||||
$this->assertFalse(tenancy()->initialized);
|
||||
|
||||
$this
|
||||
->get('http://foobar.localhost/foo/abc/xyz')
|
||||
->assertSee('abc + xyz');
|
||||
|
||||
$this->assertTrue(tenancy()->initialized);
|
||||
$this->assertSame('acme', tenant('id'));
|
||||
}
|
||||
}
|
||||
|
||||
class Tenant extends Models\Tenant
|
||||
{
|
||||
use HasDomains;
|
||||
}
|
||||
|
|
@ -15,6 +15,9 @@ class SubdomainTest extends TestCase
|
|||
{
|
||||
parent::setUp();
|
||||
|
||||
// Global state cleanup after some tests
|
||||
InitializeTenancyBySubdomain::$onInvalidSubdomain = null;
|
||||
|
||||
Route::group([
|
||||
'middleware' => InitializeTenancyBySubdomain::class,
|
||||
], function () {
|
||||
|
|
@ -93,6 +96,29 @@ class SubdomainTest extends TestCase
|
|||
->get('http://127.0.0.1/foo/abc/xyz')
|
||||
->assertSee('foo custom invalid subdomain handler');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function we_cant_use_a_subdomain_that_doesnt_belong_to_our_central_domains()
|
||||
{
|
||||
config(['tenancy.central_domains' => [
|
||||
'127.0.0.1',
|
||||
// not 'localhost'
|
||||
]]);
|
||||
|
||||
$tenant = Tenant::create([
|
||||
'id' => 'acme',
|
||||
]);
|
||||
|
||||
$tenant->domains()->create([
|
||||
'domain' => 'foo',
|
||||
]);
|
||||
|
||||
$this->expectException(NotASubdomainException::class);
|
||||
|
||||
$this
|
||||
->withoutExceptionHandling()
|
||||
->get('http://foo.localhost/foo/abc/xyz');
|
||||
}
|
||||
}
|
||||
|
||||
class Tenant extends Models\Tenant
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue