Implement basic login function; add basic styling

This commit is contained in:
Lexi / Zoe 2021-07-26 23:52:59 +02:00
parent 2bb7ea54a2
commit 8be7988d97
Signed by: binaryDiv
GPG Key ID: F8D4956E224DA232
12 changed files with 252 additions and 27 deletions

View File

@ -9,6 +9,8 @@ use MailAccountAdmin\Routes;
use MailAccountAdmin\Settings;
use Slim\Factory\AppFactory;
session_start();
$settings = new Settings();
$container = Dependencies::createContainer($settings);
$app = AppFactory::createFromContainer($container);

50
public/static/style.css Normal file
View File

@ -0,0 +1,50 @@
html, body {
max-width: 100%;
margin: 0;
padding: 0;
}
* {
box-sizing: border-box;
}
body {
font-family: sans-serif;
}
/* --- Header --- */
header {
margin: 1em;
}
header h1 {
margin: 1em;
}
/* --- Login page --- */
main.login_page {
margin: 2em;
padding: 1em;
border: 1px gray solid;
width: auto;
}
main.login_page h2 {
margin: 0 0 0.5em 0;
}
main.login_page table td {
padding: 0.2em;
}
/* --- Text and other styling --- */
.error {
background: #ff4444;
width: 30em;
margin: 1em 0;
padding: 1em;
}
button {
padding: 0.2em 1em;
}

View File

@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
namespace MailAccountAdmin\Auth;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Slim\Psr7\Response;
class AuthMiddleware implements MiddlewareInterface
{
/**
* {@inheritdoc}
*/
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
$uri = $request->getUri();
// TODO: Lots of stuff. Session middleware, auth handler class, etc...
if ($uri->getPath() !== '/login') {
// Check authorization via session
if (empty($_SESSION['username'])) {
// Not logged in -> Redirect to /login
$response = new Response();
return $response
->withHeader('Location', '/login')
->withStatus(303);
}
}
return $handler->handle($request);
}
}

View File

@ -4,7 +4,8 @@ declare(strict_types=1);
namespace MailAccountAdmin;
use DI\Container;
use MailAccountAdmin\Login\LoginController;
use MailAccountAdmin\Frontend\Login\LoginController;
use MailAccountAdmin\Frontend\Dashboard\DashboardController;
use PDO;
use Psr\Container\ContainerInterface;
use Slim\Views\Twig;
@ -47,13 +48,20 @@ class Dependencies
);
});
// Login, registration, authentication
// Login page
$container->set(LoginController::class, function (ContainerInterface $c) {
return new LoginController(
$c->get(self::TWIG)
);
});
// Dashboard
$container->set(DashboardController::class, function (ContainerInterface $c) {
return new DashboardController(
$c->get(self::TWIG)
);
});
return $container;
}
}

View File

@ -1,13 +1,13 @@
<?php
declare(strict_types=1);
namespace MailAccountAdmin\Login;
namespace MailAccountAdmin\Frontend\Dashboard;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Views\Twig;
class LoginController
class DashboardController
{
/** @var Twig */
private $view;
@ -17,11 +17,12 @@ class LoginController
$this->view = $view;
}
public function showLoginPage(Request $request, Response $response): Response
public function showDashboard(Request $request, Response $response): Response
{
$renderData = [
'username' => $_SESSION['username'],
];
return $this->view->render($response, 'login.html', $renderData);
return $this->view->render($response, 'dashboard.html.twig', $renderData);
}
}

View File

@ -0,0 +1,63 @@
<?php
declare(strict_types=1);
namespace MailAccountAdmin\Frontend\Login;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Exception\HttpBadRequestException;
use Slim\Views\Twig;
class LoginController
{
/** @var Twig */
private $view;
public function __construct(Twig $view)
{
$this->view = $view;
}
public function showLoginPage(Request $request, Response $response): Response
{
if (!empty($_SESSION['username'])) {
// Already logged in, redirect to dashboard
return $response
->withHeader('Location', '/')
->withStatus(303);
}
$renderData = [
];
return $this->view->render($response, 'login.html.twig', $renderData);
}
public function authenticateUser(Request $request, Response $response): Response
{
$params = (array)$request->getParsedBody();
if (empty($params['username']) || empty($params['password'])) {
throw new HttpBadRequestException($request, 'Missing parameters');
}
// TODO: only for testing, obviously
if ($params['username'] === 'lexi' && $params['password'] === 'testpw') {
$_SESSION['username'] = $params['username'];
return $response
->withHeader('Location', '/')
->withStatus(303);
} else {
return $this->view->render($response, 'login.html.twig', ['error' => 'Wrong username or password!']);
}
}
public function logoutUser(Request $request, Response $response): Response
{
session_destroy();
return $response
->withHeader('Location', '/login')
->withStatus(303);
}
}

View File

@ -3,6 +3,7 @@ declare(strict_types=1);
namespace MailAccountAdmin;
use MailAccountAdmin\Auth\AuthMiddleware;
use Slim\App;
use Slim\Views\TwigMiddleware;
@ -13,6 +14,7 @@ class Middlewares
$displayErrorDetails = $settings->isDebugMode();
$app->addErrorMiddleware($displayErrorDetails, true, true);
$app->add(new AuthMiddleware());
$app->add(TwigMiddleware::createFromContainer($app));
}
}

View File

@ -3,13 +3,20 @@ declare(strict_types=1);
namespace MailAccountAdmin;
use MailAccountAdmin\Login\LoginController;
use MailAccountAdmin\Frontend\Dashboard\DashboardController;
use MailAccountAdmin\Frontend\Login\LoginController;
use Slim\App;
class Routes
{
public static function setRoutes(App $app): void
{
$app->get('/', LoginController::class . ':showLoginPage');
// Login
$app->get('/login', LoginController::class . ':showLoginPage');
$app->post('/login', LoginController::class . ':authenticateUser');
$app->get('/logout', LoginController::class . ':logoutUser');
// Dashboard
$app->get('/', DashboardController::class . ':showDashboard');
}
}

23
templates/base.html.twig Normal file
View File

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>{% block title %}Untitled page{% endblock %} - MailAccountAdmin</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="/static/style.css">
</head>
<body>
<header>
<h1>MailAccountAdmin</h1>
</header>
<main>
{% block content %}
Nothing to see here...
{% endblock %}
</main>
</body>
</html>

View File

@ -0,0 +1,11 @@
{% extends "base.html.twig" %}
{% block title %}Dashboard{% endblock %}
{% block content %}
<h2>Dashboard</h2>
<p>Hello, {{ username }}!</p>
<a href="/logout">Logout.</a>
{% endblock %}

View File

@ -1,19 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>MailAccountAdmin</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- <link rel="stylesheet" href=""> -->
</head>
<body>
<h1>MailAccountAdmin - Login</h1>
<b>Hello.</b>
<!-- <script src="" async defer></script> -->
</body>
</html>

42
templates/login.html.twig Normal file
View File

@ -0,0 +1,42 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Login - MailAccountAdmin</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="/static/style.css">
</head>
<body>
<header>
<h1>MailAccountAdmin</h1>
</header>
<main class="login_page">
<h2>Login</h2>
<form action="/login" method="POST">
{% if error is defined %}
<div class="error">{{ error }}</div>
{% endif %}
<table>
<tr>
<td><label for="username">Username</label></td>
<td><input type="text" id="username" name="username"></td>
</tr>
<tr>
<td><label for="password">Password</label></td>
<td><input type="password" id="password" name="password"></td>
</tr>
<tr>
<td></td>
<td><button type="submit">Login</button></td>
</tr>
</table>
</form>
</main>
</body>
</html>