jidaikobo-shibata /
kontiki-framework
| 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: