Initial Version
This commit is contained in:
144
core/lib/Controllers/DefaultController.php
Normal file
144
core/lib/Controllers/DefaultController.php
Normal file
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
|
||||
namespace KTXC\Controllers;
|
||||
|
||||
use DI\Attribute\Inject;
|
||||
use KTXC\Http\Response\Response;
|
||||
use KTXC\Http\Response\FileResponse;
|
||||
use KTXC\Http\Response\JsonResponse;
|
||||
use KTXC\Http\Response\RedirectResponse;
|
||||
use KTXF\Controller\ControllerAbstract;
|
||||
use KTXF\Routing\Attributes\AnonymousRoute;
|
||||
use KTXC\Service\SecurityService;
|
||||
use KTXC\SessionIdentity;
|
||||
use KTXC\Http\Request\Request;
|
||||
|
||||
class DefaultController extends ControllerAbstract
|
||||
{
|
||||
public function __construct(
|
||||
private readonly SecurityService $securityService,
|
||||
private readonly SessionIdentity $identity,
|
||||
#[Inject('rootDir')] private readonly string $rootDir,
|
||||
) {}
|
||||
|
||||
#[AnonymousRoute('/', name: 'root', methods: ['GET'])]
|
||||
public function home(Request $request): Response
|
||||
{
|
||||
// If an authenticated identity is available, serve the private app
|
||||
if ($this->identity->identifier()) {
|
||||
return new FileResponse(
|
||||
$this->rootDir . '/public/private.html',
|
||||
Response::HTTP_OK,
|
||||
['Content-Type' => 'text/html']
|
||||
);
|
||||
}
|
||||
|
||||
// User is not authenticated - serve the public app
|
||||
// If there's an accessToken cookie present but invalid, clear it
|
||||
$response = new FileResponse(
|
||||
$this->rootDir . '/public/public.html',
|
||||
Response::HTTP_OK,
|
||||
['Content-Type' => 'text/html']
|
||||
);
|
||||
|
||||
// Clear any stale auth cookies since the user is not authenticated
|
||||
if ($request->cookies->has('accessToken')) {
|
||||
$response->headers->clearCookie('accessToken', '/');
|
||||
}
|
||||
if ($request->cookies->has('refreshToken')) {
|
||||
$response->headers->clearCookie('refreshToken', '/security/refresh');
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
#[AnonymousRoute('/login', name: 'login', methods: ['GET'])]
|
||||
public function login(): Response
|
||||
{
|
||||
return new FileResponse(
|
||||
$this->rootDir . '/public/public.html',
|
||||
Response::HTTP_OK,
|
||||
['Content-Type' => 'text/html']
|
||||
);
|
||||
}
|
||||
|
||||
#[AnonymousRoute('/logout', name: 'logout_get', methods: ['GET'])]
|
||||
public function logoutGet(Request $request): Response
|
||||
{
|
||||
// Blacklist the current access token if present
|
||||
$accessToken = $request->cookies->get('accessToken');
|
||||
if ($accessToken) {
|
||||
$claims = $this->securityService->extractTokenClaims($accessToken);
|
||||
if ($claims && isset($claims['jti'])) {
|
||||
$this->securityService->logout($claims['jti'], $claims['exp'] ?? null);
|
||||
}
|
||||
}
|
||||
|
||||
$response = new RedirectResponse(
|
||||
'/login',
|
||||
Response::HTTP_SEE_OTHER
|
||||
);
|
||||
|
||||
// Clear both authentication cookies
|
||||
$response->headers->clearCookie('accessToken', '/');
|
||||
$response->headers->clearCookie('refreshToken', '/security/refresh');
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
#[AnonymousRoute('/logout', name: 'logout_post', methods: ['POST'])]
|
||||
public function logoutPost(Request $request): Response
|
||||
{
|
||||
// Blacklist the current access token if present
|
||||
$accessToken = $request->cookies->get('accessToken');
|
||||
if ($accessToken) {
|
||||
$claims = $this->securityService->extractTokenClaims($accessToken);
|
||||
if ($claims && isset($claims['jti'])) {
|
||||
$this->securityService->logout($claims['jti'], $claims['exp'] ?? null);
|
||||
}
|
||||
}
|
||||
|
||||
$response = new JsonResponse(['message' => 'Logged out successfully']);
|
||||
|
||||
// Clear both authentication cookies
|
||||
$response->headers->clearCookie('accessToken', '/');
|
||||
$response->headers->clearCookie('refreshToken', '/security/refresh');
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Catch-all route for SPA routing.
|
||||
* Serves the appropriate HTML based on authentication status,
|
||||
* allowing client-side routing to handle the actual path.
|
||||
*/
|
||||
#[AnonymousRoute('/{path}', name: 'spa_catchall', methods: ['GET'])]
|
||||
public function catchAll(Request $request, string $path = ''): Response
|
||||
{
|
||||
// If an authenticated identity is available, serve the private app
|
||||
if ($this->identity->identifier()) {
|
||||
return new FileResponse(
|
||||
$this->rootDir . '/public/private.html',
|
||||
Response::HTTP_OK,
|
||||
['Content-Type' => 'text/html']
|
||||
);
|
||||
}
|
||||
|
||||
// User is not authenticated - serve the public app
|
||||
$response = new FileResponse(
|
||||
$this->rootDir . '/public/public.html',
|
||||
Response::HTTP_OK,
|
||||
['Content-Type' => 'text/html']
|
||||
);
|
||||
|
||||
// Clear any stale auth cookies since the user is not authenticated
|
||||
if ($request->cookies->has('accessToken')) {
|
||||
$response->headers->clearCookie('accessToken', '/');
|
||||
}
|
||||
if ($request->cookies->has('refreshToken')) {
|
||||
$response->headers->clearCookie('refreshToken', '/security/refresh');
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user