1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Jidaikobo\Kontiki\Controllers; |
4
|
|
|
|
5
|
|
|
use Psr\Http\Message\ResponseInterface as Response; |
6
|
|
|
use Psr\Http\Message\ServerRequestInterface as Request; |
7
|
|
|
use Slim\App; |
8
|
|
|
use Slim\Views\PhpRenderer; |
9
|
|
|
use Jidaikobo\Kontiki\Core\Auth; |
10
|
|
|
use Jidaikobo\Kontiki\Managers\CsrfManager; |
11
|
|
|
use Jidaikobo\Kontiki\Managers\FlashManager; |
12
|
|
|
use Jidaikobo\Kontiki\Models\UserModel; |
13
|
|
|
use Jidaikobo\Kontiki\Services\FormService; |
14
|
|
|
use Jidaikobo\Kontiki\Services\RateLimitService; |
15
|
|
|
use Jidaikobo\Kontiki\Services\RoutesService; |
16
|
|
|
|
17
|
|
|
class AuthController extends BaseController |
18
|
|
|
{ |
19
|
|
|
private Auth $auth; |
20
|
|
|
private FormService $formService; |
21
|
|
|
private RateLimitService $rateLimitService; |
22
|
|
|
private UserModel $model; |
23
|
|
|
|
24
|
|
|
public function __construct( |
25
|
|
|
CsrfManager $csrfManager, |
26
|
|
|
FlashManager $flashManager, |
27
|
|
|
PhpRenderer $view, |
28
|
|
|
RoutesService $routesService, |
29
|
|
|
Auth $auth, |
30
|
|
|
FormService $formService, |
31
|
|
|
RateLimitService $rateLimitService, |
32
|
|
|
UserModel $model |
33
|
|
|
) { |
34
|
|
|
parent::__construct( |
35
|
|
|
$csrfManager, |
36
|
|
|
$flashManager, |
37
|
|
|
$view, |
38
|
|
|
$routesService |
39
|
|
|
); |
40
|
|
|
$this->auth = $auth; |
41
|
|
|
$this->formService = $formService; |
42
|
|
|
$this->formService->setModel($model); |
43
|
|
|
$this->rateLimitService = $rateLimitService; |
44
|
|
|
$this->model = $model; |
45
|
|
|
} |
46
|
|
|
|
47
|
|
|
public static function registerRoutes(App $app, string $basePath = ''): void |
48
|
|
|
{ |
49
|
|
|
$app->get('/login', AuthController::class . ':showLoginForm')->setName('login'); |
50
|
|
|
$app->post('/login', AuthController::class . ':processLogin'); |
51
|
|
|
$app->get('/logout', AuthController::class . ':logout'); |
52
|
|
|
} |
53
|
|
|
|
54
|
|
|
public function showLoginForm(Request $request, Response $response): Response |
55
|
|
|
{ |
56
|
|
|
$ip = $_SERVER['REMOTE_ADDR'] ?? 'UNKNOWN'; |
57
|
|
|
if ($this->rateLimitService->isIpBlocked($ip)) { |
58
|
|
|
http_response_code(403); |
59
|
|
|
die("Access denied due to too many failed login attempts."); |
|
|
|
|
60
|
|
|
} |
61
|
|
|
|
62
|
|
|
if ($this->auth->isLoggedIn()) { |
63
|
|
|
return $this->redirectResponse($request, $response, 'dashboard'); |
64
|
|
|
} |
65
|
|
|
|
66
|
|
|
$data = $this->flashManager->getData('data', ['username' => '']); |
67
|
|
|
|
68
|
|
|
$content = $this->view->fetch('auth/login.php', $data); |
69
|
|
|
$content = $this->formService->addMessages( |
70
|
|
|
$content, |
71
|
|
|
$this->flashManager->getData('errors', []) |
72
|
|
|
); |
73
|
|
|
|
74
|
|
|
return $this->renderResponse( |
75
|
|
|
$response, |
76
|
|
|
__('login', 'Login'), |
77
|
|
|
$content, |
78
|
|
|
'layout-simple.php' |
79
|
|
|
); |
80
|
|
|
} |
81
|
|
|
|
82
|
|
|
public function processLogin(Request $request, Response $response): Response |
83
|
|
|
{ |
84
|
|
|
$data = $request->getParsedBody() ?? []; |
85
|
|
|
$username = $data['username'] ?? ''; |
86
|
|
|
$password = $data['password'] ?? ''; |
87
|
|
|
$ip = $_SERVER['REMOTE_ADDR'] ?? 'UNKNOWN'; |
88
|
|
|
|
89
|
|
|
if ($this->auth->login($username, $password)) { |
90
|
|
|
$this->rateLimitService->resetRateLimit($ip); |
91
|
|
|
$this->rateLimitService->cleanOldRateLimitData(); |
92
|
|
|
return $this->redirectResponse($request, $response, 'dashboard'); |
93
|
|
|
} |
94
|
|
|
|
95
|
|
|
$this->rateLimitService->recordFailedLogin($ip); |
96
|
|
|
$this->flashManager->addErrors([ |
97
|
|
|
['messages' => [__('wrong_username_or_password', 'Incorrect username or password')]], |
98
|
|
|
]); |
99
|
|
|
$this->flashManager->setData('data', ['username' => $username]); // not keep password |
100
|
|
|
return $this->redirectResponse($request, $response, 'login'); |
101
|
|
|
} |
102
|
|
|
|
103
|
|
|
public function logout(Request $request, Response $response): Response |
104
|
|
|
{ |
105
|
|
|
$this->auth->logout(); |
106
|
|
|
return $this->redirectResponse($request, $response, 'login'); |
107
|
|
|
} |
108
|
|
|
} |
109
|
|
|
|
For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example: