Commit da566b89 authored by Jacob Priddy's avatar Jacob Priddy 👌
Browse files

Token authentication!

parent 3127edcd
......@@ -10,6 +10,8 @@ use Illuminate\Http\Request;
use Illuminate\Auth\GuardHelpers;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Contracts\Auth\Authenticatable;
use Source\UseCases\Token\Authenticate\AuthenticateUseCase;
use Source\UseCases\Token\Authenticate\TranslationPresenter;
class ApiGuard implements Guard {
use GuardHelpers;
......@@ -35,21 +37,25 @@ class ApiGuard implements Guard {
*/
protected string $storageKey;
protected AuthenticateUseCase $authenticator;
/**
* Create a new authentication guard.
*
* @param AuthenticateUseCase $authenticator
* @param Request $request
* @param string $inputKey
* @param string $storageKey
* @return void
*/
public function __construct(
AuthenticateUseCase $authenticator,
Request $request,
$inputKey = 'api_token',
$storageKey = 'api_token') {
$this->request = $request;
$this->inputKey = $inputKey;
$this->storageKey = $storageKey;
$this->authenticator = $authenticator;
}
/**
......@@ -135,10 +141,10 @@ class ApiGuard implements Guard {
* @return Authenticatable|null
*/
public function retrieveByToken(string $token): ?Authenticatable {
$token = Token::where($this->storageKey, $token)->first();
if ($token) {
return $token->user()->first();
}
return null;
$presenter = new TranslationPresenter();
$this->authenticator->check($presenter, $token);
return $presenter->getViewModel();
}
}
......@@ -3,14 +3,14 @@
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Source\UseCases\Users\GetUser\GetUserUseCase;
use Source\Gateways\Users\UsersRepositoryServiceProvider;
use Source\UseCases\Users\GetAllUsers\GetAllUsersUseCase;
use Source\Gateways\Tokens\TokensRepositoryServiceProvider;
use Source\UseCases\Users\GetUser\GetUserUseCaseServiceProvider;
use Source\UseCases\Users\CreateUser\CreateUserUseCaseServiceProvider;
use Source\UseCases\Users\DeleteUser\DeleteUserUseCaseServiceProvider;
use Source\UseCases\Users\UpdateUser\UpdateUserUseCaseServiceProvider;
use Source\UseCases\Users\GetAllUsers\GetAllUsersUseCaseServiceProvider;
use Source\UseCases\Token\Authenticate\AuthenticateUseCaseServiceProvider;
class AppServiceProvider extends ServiceProvider
{
......@@ -20,6 +20,7 @@ class AppServiceProvider extends ServiceProvider
*/
protected array $gatewayProviders = [
UsersRepositoryServiceProvider::class,
TokensRepositoryServiceProvider::class,
];
/**
......@@ -31,6 +32,8 @@ class AppServiceProvider extends ServiceProvider
UpdateUserUseCaseServiceProvider::class,
CreateUserUseCaseServiceProvider::class,
GetAllUsersUseCaseServiceProvider::class,
AuthenticateUseCaseServiceProvider::class,
];
/**
......
......@@ -4,6 +4,7 @@ namespace App\Providers;
use App\Guards\ApiGuard;
use Illuminate\Support\Facades\Auth;
use Source\UseCases\Token\Authenticate\AuthenticateUseCase;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
class AuthServiceProvider extends ServiceProvider {
......@@ -28,7 +29,7 @@ class AuthServiceProvider extends ServiceProvider {
Auth::extend(
'api',
static function ($app, $name, array $config) {
return new ApiGuard($app['request']);
return new ApiGuard($app->make(AuthenticateUseCase::class), $app['request']);
}
);
}
......
......@@ -9,6 +9,10 @@ use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable {
use SoftDeletes;
protected $fillable = [
'*',
];
/**
* The attributes that should be cast to native types.
*
......
......@@ -38,9 +38,9 @@ class User {
protected string $email;
/**
* @var string
* @var string|null
*/
protected string $password;
protected ?string $password;
/**
* @var string
......@@ -81,7 +81,7 @@ class User {
string $displayName,
?string $emplid,
string $email,
string $password,
?string $password,
string $doorcode,
?Carbon $expiresAt,
?Carbon $createdAt,
......@@ -142,9 +142,9 @@ class User {
}
/**
* @return string
* @return string|null
*/
public function getPassword(): string {
public function getPassword(): ?string {
return $this->password;
}
......@@ -196,6 +196,9 @@ class User {
}
public function matchCredentials(?string $email, ?string $password): bool {
if (!$password || !$email) {
return false;
}
return $this->getEmail() === $email && $this->getPassword() === $password;
}
......
......@@ -10,6 +10,6 @@ use Source\Entities\Token;
class LocalTokensRepository extends InMemoryTokensRepository {
public function __construct() {
$this->tokens[] = new Token(1, 1, 'token_string', 'basic token');
$this->tokens[] = new Token(2, 420, 'expired token', Carbon::now()->subDays(3));
$this->tokens[] = new Token(2, 420, 'expired_token', '', Carbon::now()->subDays(3));
}
}
......@@ -4,7 +4,6 @@
namespace Source\Gateways\Tokens;
use Source\Entities\User;
use Source\Entities\Token;
use Source\Exceptions\EntityNotFoundException;
......@@ -18,7 +17,7 @@ interface TokensRepository {
/**
* @param string $token
* @return User|null
* @return Token|null
*/
public function findByToken(string $token): ?Token;
}
......@@ -107,6 +107,7 @@ class DatabaseUsersRepository implements UsersRepository {
$dbUser->email = $user->getEmail();
$dbUser->password = bcrypt($user->getPassword());
$dbUser->doorcode = hash('sha256', $user->getDoorcode());
$dbUser->expires_at = $user->getExpiresAt();
$dbUser->save();
......
<?php
namespace Source\UseCases\Token\Authenticate;
use Source\Entities\User;
use Source\Gateways\Users\UsersRepository;
use Source\Gateways\Tokens\TokensRepository;
class Authenticate implements AuthenticateUseCase {
protected TokensRepository $tokens;
protected UsersRepository $users;
/**
* @param TokensRepository $tokens
* @param UsersRepository $users
*/
public function __construct(TokensRepository $tokens, UsersRepository $users) {
$this->tokens = $tokens;
$this->users = $users;
}
/**
* @inheritDoc
*/
public function check(Presenter $presenter, ?string $token): void {
if (!$token) {
return;
}
$found = $this->tokens->findByToken($token);
if (!$found) {
return;
}
$response = new ResponseModel();
$user = $this->users->get($found->getUserId());
$response->setUser($user);
$presenter->present($response);
}
}
<?php
namespace Source\UseCases\Token\Authenticate;
interface AuthenticateUseCase {
/**
* Authenticates an API token
*
* @param Presenter $presenter
* @param string|null $token
*/
public function check(Presenter $presenter, ?string $token): void;
}
<?php
namespace Source\UseCases\Token\Authenticate;
use Illuminate\Support\ServiceProvider;
use Source\Gateways\Users\UsersRepository;
use Source\Gateways\Tokens\TokensRepository;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Contracts\Support\DeferrableProvider;
/**
* Service provider must be registered in AppServiceProvider
*/
class AuthenticateUseCaseServiceProvider extends ServiceProvider implements DeferrableProvider {
/**
* Register any application services.
*
* @return void
*/
public function register() {
$this->app->bind(
AuthenticateUseCase::class,
static function (Application $app) {
return new Authenticate($app->make(TokensRepository::class), $app->make(UsersRepository::class));
}
);
}
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot(): void {
}
/**
* @return array
*/
public function provides() {
return [AuthenticateUseCase::class];
}
}
<?php
namespace Source\UseCases\Token\Authenticate;
use App\User;
interface Presenter {
/**
* @param ResponseModel $responseModel
* @return void
*/
public function present(ResponseModel $responseModel): void;
/**
* @return User|null
*/
public function getViewModel(): ?User;
}
<?php
namespace Source\UseCases\Token\Authenticate;
use Source\Entities\User;
class ResponseModel {
protected ?User $user = null;
/**
* @param User|null $user
*/
public function setUser(?User $user): void {
$this->user = $user;
}
/**
* @return User|null
*/
public function getUser(): ?User {
return $this->user;
}
}
<?php
namespace Source\UseCases\Token\Authenticate;
use App\User;
use Source\UseCases\BasePresenter;
class TranslationPresenter extends BasePresenter implements Presenter {
protected ?User $viewModel = null;
/** @inheritDoc */
public function present(ResponseModel $responseModel): void {
$user = $responseModel->getUser();
if (!$user) {
return;
}
$dbUser = new User();
$dbUser->id = $user->getId();
$dbUser->email = $user->getEmail();
$dbUser->first_name = $user->getFirstName();
$dbUser->last_name = $user->getLastName();
$dbUser->display_name = $user->getDisplayName();
$dbUser->emplid = $user->getEmplid();
$dbUser->created_at = $user->getCreatedAt();
$dbUser->expires_at = $user->getExpiresAt();
$dbUser->updated_at = $user->getUpdatedAt();
$this->viewModel = $dbUser;
}
/** @inheritDoc */
public function getViewModel(): ?User {
return $this->viewModel;
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment