1
0
Fork 0
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:
Samuel Štancl 2020-05-10 19:30:01 +02:00
parent 8ea4940f34
commit f328fc9c08
4 changed files with 141 additions and 4 deletions

View 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'));
}
}

View file

@ -7,6 +7,7 @@ namespace Stancl\Tenancy\Middleware;
use Closure; use Closure;
use Illuminate\Http\Response; use Illuminate\Http\Response;
use Stancl\Tenancy\Exceptions\NotASubdomainException; use Stancl\Tenancy\Exceptions\NotASubdomainException;
use Illuminate\Support\Str;
class InitializeTenancyBySubdomain extends InitializeTenancyByDomain class InitializeTenancyBySubdomain extends InitializeTenancyByDomain
{ {
@ -51,7 +52,10 @@ class InitializeTenancyBySubdomain extends InitializeTenancyByDomain
$parts = explode('.', $hostname); $parts = explode('.', $hostname);
// If we're on localhost or an IP address, then we're not visiting a subdomain. // 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) { $handle = static::$onInvalidSubdomain ?? function ($e) {
throw $e; throw $e;
}; };
@ -59,9 +63,6 @@ class InitializeTenancyBySubdomain extends InitializeTenancyByDomain
return $handle(new NotASubdomainException($hostname)); 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]; return $parts[static::$subdomainIndex];
} }
} }

View 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;
}

View file

@ -15,6 +15,9 @@ class SubdomainTest extends TestCase
{ {
parent::setUp(); parent::setUp();
// Global state cleanup after some tests
InitializeTenancyBySubdomain::$onInvalidSubdomain = null;
Route::group([ Route::group([
'middleware' => InitializeTenancyBySubdomain::class, 'middleware' => InitializeTenancyBySubdomain::class,
], function () { ], function () {
@ -93,6 +96,29 @@ class SubdomainTest extends TestCase
->get('http://127.0.0.1/foo/abc/xyz') ->get('http://127.0.0.1/foo/abc/xyz')
->assertSee('foo custom invalid subdomain handler'); ->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 class Tenant extends Models\Tenant