-
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(User): Add ability to auto login a user via Auto-Login header in…
… local environment 1. Use `LaraStrict\User\Http\Middlewares\Authenticate` middleware 2. Implement `GetUserForAutoLoginActionContract` (add it to App/User/Actions) 3. Bind your implementation in service provider (your UserServiceProvider or AppServiceProvider) ```php class UserServiceProvider extends ServiceProvider { public array $bindings = [ GetUserForAutoLoginActionContract::class => GetUserForAutoLoginAction::class, ]; } ```
- Loading branch information
Showing
4 changed files
with
211 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace LaraStrict\User\Contracts; | ||
|
||
use Illuminate\Contracts\Auth\Authenticatable; | ||
|
||
interface GetUserForAutoLoginActionContract | ||
{ | ||
public function execute(string $autoLogin): ?Authenticatable; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace LaraStrict\User\Http\Middlewares; | ||
|
||
use Illuminate\Auth\Middleware\Authenticate as Middleware; | ||
use Illuminate\Contracts\Auth\Factory as Auth; | ||
use Illuminate\Contracts\Foundation\Application; | ||
use Illuminate\Http\Request; | ||
use LaraStrict\Enums\EnvironmentType; | ||
use LaraStrict\User\Contracts\GetUserForAutoLoginActionContract; | ||
|
||
class Authenticate extends Middleware | ||
{ | ||
public function __construct( | ||
Auth $auth, | ||
private readonly Application $application, | ||
private readonly GetUserForAutoLoginActionContract $getUserForAutoLoginActionContract, | ||
) { | ||
parent::__construct($auth); | ||
} | ||
|
||
protected function authenticate($request, array $guards): void | ||
{ | ||
if (empty($guards)) { | ||
$guards = [null]; | ||
} | ||
|
||
$this->autoLoginFirstUserOnLocalIfNeeded($request, $guards); | ||
|
||
parent::authenticate($request, $guards); | ||
} | ||
|
||
/** | ||
* Get the path the user should be redirected to when they are not authenticated. | ||
* | ||
* @param Request $request | ||
* | ||
* @return string|null | ||
*/ | ||
protected function redirectTo($request) | ||
{ | ||
if ($request->expectsJson() === false) { | ||
return route('login'); | ||
} | ||
} | ||
|
||
protected function autoLoginFirstUserOnLocalIfNeeded(Request $request, array $guards): void | ||
{ | ||
$autoLogin = $request->header('Auto-Login'); | ||
if ($this->application->environment([EnvironmentType::Local->value]) === false || | ||
$autoLogin === null) { | ||
return; | ||
} | ||
|
||
foreach ($guards as $guard) { | ||
$guardInstance = $this->auth->guard($guard); | ||
|
||
if ($guardInstance->check()) { | ||
break; | ||
} | ||
|
||
$user = $this->getUserForAutoLoginActionContract->execute($autoLogin); | ||
|
||
if ($user !== null) { | ||
$guardInstance->setUser($user); | ||
} | ||
|
||
break; | ||
} | ||
} | ||
} |
102 changes: 102 additions & 0 deletions
102
tests/Feature/User/Http/Middlewares/AuthenticateTest.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Tests\LaraStrict\Feature\User\Http\Middlewares; | ||
|
||
use Illuminate\Auth\AuthenticationException; | ||
use LaraStrict\Enums\EnvironmentType; | ||
use LaraStrict\Testing\Concerns\CreateRequest; | ||
use LaraStrict\Testing\Concerns\TestData; | ||
use LaraStrict\User\Contracts\GetUserForAutoLoginActionContract; | ||
use LaraStrict\User\Http\Middlewares\Authenticate; | ||
use Tests\LaraStrict\Feature\TestCase; | ||
use Tests\LaraStrict\Feature\Testing\Concerns\TestRequest; | ||
use const true; | ||
|
||
class AuthenticateTest extends TestCase | ||
{ | ||
use CreateRequest; | ||
use TestData; | ||
|
||
public function data(): array | ||
{ | ||
return [ | ||
'empty string' => [ | ||
static fn (self $self) => $self->assert(value: '', expectedValue: '',), | ||
], | ||
'true' => [ | ||
static fn (self $self) => $self->assert(value: true, expectedValue: '1',), | ||
], | ||
'false' => [ | ||
static fn (self $self) => $self->assert(value: false, expectedValue: '',), | ||
], | ||
'true string' => [ | ||
static fn (self $self) => $self->assert(value: 'true', expectedValue: 'true',), | ||
], | ||
'false string' => [ | ||
static fn (self $self) => $self->assert(value: 'false', expectedValue: 'false',), | ||
], | ||
'null' => [ | ||
static fn (self $self) => $self->assert(value: null, expectedValue: null,), | ||
], | ||
'valid but different env - testing' => [ | ||
static fn (self $self) => $self->assert( | ||
value: '1', | ||
expectedValue: null, | ||
environment: EnvironmentType::Testing, | ||
), | ||
], | ||
'valid but different env - production' => [ | ||
static fn (self $self) => $self->assert( | ||
value: '1', | ||
expectedValue: null, | ||
environment: EnvironmentType::Production, | ||
), | ||
], | ||
]; | ||
} | ||
|
||
public function assert( | ||
string|bool|null $value, | ||
string|null $expectedValue, | ||
EnvironmentType $environment = EnvironmentType::Local, | ||
): void { | ||
$this->app() | ||
->detectEnvironment(static fn () => $environment->value); | ||
|
||
$request = $this->createPostRequest( | ||
application: $this->app(), | ||
requestClass: TestRequest::class, | ||
data: [ | ||
'test' => 'test', | ||
], | ||
server: $value === null ? [] : [ | ||
'HTTP_Auto-Login' => $value, | ||
] | ||
); | ||
|
||
$this->app() | ||
->bind( | ||
GetUserForAutoLoginActionContract::class, | ||
static fn () => new GetUserForAutoLoginTestAction($expectedValue) | ||
); | ||
|
||
/** @var Authenticate $middleware */ | ||
$middleware = $this->app() | ||
->make(Authenticate::class); | ||
|
||
if ($expectedValue === null) { | ||
$this->expectException(AuthenticationException::class); | ||
$middleware->handle($request, static function () { | ||
}); | ||
return; | ||
} | ||
|
||
$called = false; | ||
$middleware->handle($request, static function () use (&$called) { | ||
$called = true; | ||
}); | ||
$this->assertEquals(true, $called); | ||
} | ||
} |
24 changes: 24 additions & 0 deletions
24
tests/Feature/User/Http/Middlewares/GetUserForAutoLoginTestAction.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Tests\LaraStrict\Feature\User\Http\Middlewares; | ||
|
||
use Illuminate\Contracts\Auth\Authenticatable; | ||
use Illuminate\Foundation\Auth\User; | ||
use LaraStrict\User\Contracts\GetUserForAutoLoginActionContract; | ||
use PHPUnit\Framework\Assert; | ||
|
||
class GetUserForAutoLoginTestAction implements GetUserForAutoLoginActionContract | ||
{ | ||
public function __construct( | ||
private readonly ?string $expectedAutoLogin, | ||
) { | ||
} | ||
|
||
public function execute(string $autoLogin): ?Authenticatable | ||
{ | ||
Assert::assertEquals($this->expectedAutoLogin, $autoLogin, 'Auto login value'); | ||
return new User(); | ||
} | ||
} |