Skip to content

Commit

Permalink
wip: ひとまず認証処理をベタ書きで実装(「ダミーのオンメモリストレージで単にログイン/ログアウトできる」というだけのセッション実装)
Browse files Browse the repository at this point in the history
  • Loading branch information
Kimita committed Sep 18, 2022
1 parent 73d851c commit 01a4135
Show file tree
Hide file tree
Showing 11 changed files with 214 additions and 9 deletions.
10 changes: 10 additions & 0 deletions src/AppSpi/IdentityRepositoryInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

declare(strict_types=1);

namespace Cw\LearnBear\AppSpi;

interface IdentityRepositoryInterface
{
public function findByUserNameAndPassword(string $username, string $password): ?string;
}
57 changes: 57 additions & 0 deletions src/Infrastructure/Authentication/CwSession.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

declare(strict_types=1);

namespace Cw\LearnBear\Infrastructure\Authentication;

use Aura\Session\Segment;
use Aura\Session\SessionFactory;
use Aura\Web\WebFactory;
use Cw\LearnBear\AppSpi\LoggerInterface;
use Cw\LearnBear\AppSpi\SessionHandlerInterface;

class CwSession implements SessionHandlerInterface
{
private readonly Segment $segment;

/**
* @SuppressWarnings(PHPMD.Superglobals)
*/
public function __construct(private readonly LoggerInterface $logger)
{
$session = (new SessionFactory())->newInstance(
(new WebFactory($GLOBALS))->newRequest()->cookies->getArrayCopy()
);
$this->segment = $session->getSegment(self::SESS_SEGMENT);
}

public function setAuth(string $uuid): void
{
$this->segment->set('userIdentity', $uuid);
}

public function isNotAuthorized(): bool
{
$this->logger->log('userIdentity: ' . $this->segment->get('userIdentity', 'no valid session.'));

return empty($this->segment->get('userIdentity'));
}

public function clearAuth(): void
{
$this->segment->clear();
}

public function setFlashMessage(string $message, string $key): void
{
$this->segment->setFlash($key, $message);
}

public function getFlashMessage(string $key): ?string
{
$message = $this->segment->getFlash($key);
$this->segment->clearFlash();

return $message;
}
}
44 changes: 44 additions & 0 deletions src/Infrastructure/Authentication/IdentityRepository.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

declare(strict_types=1);

namespace Cw\LearnBear\Infrastructure\Authentication;

use Cw\LearnBear\AppSpi\IdentityRepositoryInterface;

use function password_hash;
use function password_verify;

use const PASSWORD_BCRYPT;

class IdentityRepository implements IdentityRepositoryInterface
{
/** @var array<string, mixed> */
private readonly array $dummyStorage;

public function __construct()
{
$this->dummyStorage = [
'hogetest' => [
'uuid' => 'ea210d8c-25b9-4f4a-b36a-a42634a9ab5c',
'password' => password_hash('Fuga.1234', PASSWORD_BCRYPT),
],
'piyotest' => [
'uuid' => 'd31ebeeb-6825-4b0e-9dee-248b7ace9ffa',
'password' => password_hash('Fuga.1234', PASSWORD_BCRYPT),
],
];
}

public function findByUserNameAndPassword(string $username, string $password): ?string
{
$identity = $this->dummyStorage[$username] ?? null;
if ($identity === null) {
return null;
}

return password_verify($password, $identity['password'])
? $identity['uuid']
: null;
}
}
1 change: 1 addition & 0 deletions src/Module/AppModule.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ protected function configure(): void
{
(new Dotenv())->load(dirname(__DIR__, 2));
$this->install(new PackageModule());
$this->install(new CwAuthModule());
$this->bind(LoggerInterface::class)->to(DebugLogger::class);
}
}
23 changes: 23 additions & 0 deletions src/Module/CwAuthModule.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace Cw\LearnBear\Module;

use Cw\LearnBear\AppSpi\IdentityRepositoryInterface;
use Cw\LearnBear\AppSpi\SessionHandlerInterface;
use Cw\LearnBear\Infrastructure\Authentication\CwSession;
use Cw\LearnBear\Infrastructure\Authentication\IdentityRepository;
use Ray\Di\AbstractModule;

class CwAuthModule extends AbstractModule
{
/**
* @inheritDoc
*/
protected function configure()
{
$this->bind(SessionHandlerInterface::class)->to(CwSession::class);
$this->bind(IdentityRepositoryInterface::class)->to(IdentityRepository::class);
}
}
16 changes: 16 additions & 0 deletions src/Resource/Page/Index.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,33 @@
namespace Cw\LearnBear\Resource\Page;

use BEAR\Resource\ResourceObject;
use Cw\LearnBear\AppSpi\LoggerInterface;
use Cw\LearnBear\AppSpi\SessionHandlerInterface;

use function var_export;

class Index extends ResourceObject
{
public function __construct(
private readonly LoggerInterface $logger,
private readonly SessionHandlerInterface $cwSession,
) {
}

public function onGet(): static
{
$flashMsg = $this->cwSession->getFlashMessage(SessionHandlerInterface::FLASH_KEY_FOR_LOGIN_FORM);
$params = $this->body ?: [];
if ($flashMsg) {
$params['flash_message'] = $flashMsg;
}

$this->body = $params + [
'_links' => [
'login' => ['href' => '/login'],
],
];
$this->logger->log(var_export([__METHOD__ . ': body' => $this->body], true));

return $this;
}
Expand Down
32 changes: 24 additions & 8 deletions src/Resource/Page/Login.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,38 @@

use BEAR\Resource\Code;
use BEAR\Resource\ResourceObject;
use Cw\LearnBear\AppSpi\LoggerInterface;
use Cw\LearnBear\AppSpi\IdentityRepositoryInterface;
use Cw\LearnBear\AppSpi\SessionHandlerInterface;
use DateTime;

use function password_hash;

use const PASSWORD_BCRYPT;

class Login extends ResourceObject
{
public function __construct(private readonly LoggerInterface $logger)
{
public function __construct(
private readonly SessionHandlerInterface $cwSession,
private readonly IdentityRepositoryInterface $identityRepository,
) {
}

public function onPost(string $username = '', string $password = ''): static
{
$this->logger->log('username: ' . $username . ', password: ' . password_hash($password, PASSWORD_BCRYPT));
// 認証処理をする
$uuid = $this->identityRepository->findByUserNameAndPassword($username, $password);
if ($uuid === null) {
$this->cwSession->setFlashMessage('ログイン認証に失敗しました', SessionHandlerInterface::FLASH_KEY_FOR_LOGIN_FORM);
$toUrl = '/index';
$this->code = Code::SEE_OTHER;
$this->headers['Location'] = $toUrl;
$this->body = [
'_links' => [
'redirect' => ['href' => $toUrl],
],
];

return $this;
}

// 認証されたPHPセッションを開始
$this->cwSession->setAuth($uuid ?: 'dummy');

// nextページを呼ぶ際に必要となるクエリ文字列(Next::onGet()の引数に相当)を準備
$now = new DateTime();
Expand Down
9 changes: 9 additions & 0 deletions src/Resource/Page/Logout.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,20 @@
namespace Cw\LearnBear\Resource\Page;

use BEAR\Resource\ResourceObject;
use Cw\LearnBear\AppSpi\SessionHandlerInterface;

class Logout extends ResourceObject
{
public function __construct(
private readonly SessionHandlerInterface $cwSession,
) {
}

public function onGet(): ResourceObject
{
// 認証されたPHPセッションを終了
$this->cwSession->clearAuth();

$this->body = $this->body ?: [];
$this->body['_links'] = [
'index' => ['href' => '/index'],
Expand Down
24 changes: 24 additions & 0 deletions src/Resource/Page/Next.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,39 @@

namespace Cw\LearnBear\Resource\Page;

use BEAR\Resource\Code;
use BEAR\Resource\RenderInterface;
use BEAR\Resource\ResourceObject;
use BEAR\Sunday\Inject\ResourceInject;
use Cw\LearnBear\AppSpi\SessionHandlerInterface;
use Ray\Di\Di\Named;

class Next extends ResourceObject
{
use ResourceInject;

public function __construct(
#[Named('error_page')] private readonly RenderInterface $errorRender,
private readonly SessionHandlerInterface $cwSession,
) {
}

public function onGet(int $year, int $month, int $day): static
{
// 認証されたPHPセッション継続をチェック
if ($this->cwSession->isNotAuthorized()) {
$this->code = Code::UNAUTHORIZED;
$this->setRenderer($this->errorRender);
$this->body = [
'status' => [
'code' => $this->code,
'message' => 'ユーザー認証をしてください',
],
];

return $this;
}

$params = ['year' => $year, 'month' => $month, 'day' => $day];
$this->body = $params + [
'weekday' => $this->resource->get('app://self/weekday', $params),
Expand Down
3 changes: 3 additions & 0 deletions var/templates/Page/Index.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
{% block content %}

<h1 id="starting-point">index</h1>
{% if flash_message is defined %}
<pre id="flash-message">{{ flash_message }}</pre>
{% endif %}
<div>
<form id="login-form" action="{{ _links.login.href }}" method="post">
<label for="username">ユーザー名</label><input id="username" type="text" name="username" value="" />
Expand Down
4 changes: 3 additions & 1 deletion var/templates/error/error.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
{% block title %}{{ status.code }} {{ status.message }}{% endblock %}
{% block content %}
<h1>{{ status.code }} {{ status.message }}</h1>
{% if status.code == 404 %}
{% if status.code == 401 %}
<p class="lead">The requested URL was unauthorized.</p>
{% elseif status.code == 404 %}
<p class="lead">The requested URL was not found on this server.</p>
{% elseif status.code == 500 %}
<p class="lead">The server encountered an internal error.</p>
Expand Down

0 comments on commit 01a4135

Please sign in to comment.