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."); |
||
0 ignored issues
–
show
|
|||
60 | } |
||
61 | |||
62 | if ($this->auth->isLoggedIn()) { |
||
63 | return $this->redirectResponse($request, $response, 'dashboard'); |
||
64 | } |
||
65 | |||
66 | $redirectUrl = $request->getQueryParams()['redirect'] ?? ''; |
||
67 | $data = $this->flashManager->getData( |
||
68 | 'data', |
||
69 | ['username' => '', 'redirectUrl' => $redirectUrl] |
||
70 | ); |
||
71 | |||
72 | $content = $this->view->fetch('auth/login.php', $data); |
||
73 | $content = $this->formService->addMessages( |
||
74 | $content, |
||
75 | $this->flashManager->getData('errors', []) |
||
76 | ); |
||
77 | |||
78 | return $this->renderResponse( |
||
79 | $response, |
||
80 | __('login', 'Login'), |
||
81 | $content, |
||
82 | 'layout-simple.php' |
||
83 | ); |
||
84 | } |
||
85 | |||
86 | public function processLogin(Request $request, Response $response): Response |
||
87 | { |
||
88 | $data = $request->getParsedBody() ?? []; |
||
89 | $username = $data['username'] ?? ''; |
||
90 | $password = $data['password'] ?? ''; |
||
91 | $redirectRaw = $data['redirectUrl'] ?? ''; |
||
92 | $redirectUrl = trim($redirectRaw) !== '' ? $redirectRaw : 'dashboard'; |
||
93 | $ip = $_SERVER['REMOTE_ADDR'] ?? 'UNKNOWN'; |
||
94 | |||
95 | // Login successful |
||
96 | if ($this->auth->login($username, $password)) { |
||
97 | $this->rateLimitService->resetRateLimit($ip); |
||
98 | $this->rateLimitService->cleanOldRateLimitData(); |
||
99 | return $this->redirectResponse($request, $response, $redirectUrl); |
||
100 | } |
||
101 | |||
102 | // Login Failed |
||
103 | $this->rateLimitService->recordFailedLogin($ip); |
||
104 | $this->flashManager->addErrors([ |
||
105 | ['messages' => [__('wrong_username_or_password', 'Incorrect username or password')]], |
||
106 | ]); |
||
107 | $this->flashManager->setData( |
||
108 | 'data', |
||
109 | ['username' => $username, 'redirectUrl' => $redirectUrl] |
||
110 | ); // not keep password |
||
111 | return $this->redirectResponse($request, $response, 'login'); |
||
112 | } |
||
113 | |||
114 | public function logout(Request $request, Response $response): Response |
||
115 | { |
||
116 | $this->auth->logout(); |
||
117 | return $this->redirectResponse($request, $response, 'login'); |
||
118 | } |
||
119 | } |
||
120 |
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: