Skip to content

Commit 722c663

Browse files
committed
PublicRoute Attr
1 parent 21d04aa commit 722c663

3 files changed

Lines changed: 98 additions & 0 deletions

File tree

src/Attribute/PublicRoute.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpList\WebFrontend\Attribute;
6+
7+
use Attribute;
8+
9+
#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)]
10+
class PublicRoute
11+
{
12+
public function __construct(public bool $isPublic = true)
13+
{
14+
}
15+
}

src/Controller/AuthController.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Exception;
88
use GuzzleHttp\Exception\GuzzleException;
99
use PhpList\RestApiClient\Endpoint\AuthClient;
10+
use PhpList\WebFrontend\Attribute\PublicRoute;
1011
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
1112
use Symfony\Component\HttpFoundation\Request;
1213
use Symfony\Component\HttpFoundation\Response;
@@ -21,6 +22,7 @@ public function __construct(AuthClient $apiClient)
2122
$this->apiClient = $apiClient;
2223
}
2324

25+
#[PublicRoute]
2426
#[Route('/login', name: 'login', methods: ['GET', 'POST'])]
2527
public function login(Request $request): Response
2628
{
@@ -64,6 +66,7 @@ public function login(Request $request): Response
6466
}
6567

6668
#[Route('/logout', name: 'logout')]
69+
#[PublicRoute]
6770
public function logout(Request $request): Response
6871
{
6972
$request->getSession()->remove('auth_token');
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpList\WebFrontend\EventSubscriber;
6+
7+
use PhpList\WebFrontend\Attribute\PublicRoute;
8+
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
9+
use Symfony\Component\HttpFoundation\RedirectResponse;
10+
use Symfony\Component\HttpKernel\Event\ControllerEvent;
11+
use Symfony\Component\HttpKernel\KernelEvents;
12+
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
13+
use ReflectionClass;
14+
use ReflectionMethod;
15+
16+
class AuthRequiredSubscriber implements EventSubscriberInterface
17+
{
18+
public function __construct(private readonly UrlGeneratorInterface $urlGenerator)
19+
{
20+
}
21+
22+
public static function getSubscribedEvents(): array
23+
{
24+
return [
25+
KernelEvents::CONTROLLER => 'onController',
26+
];
27+
}
28+
29+
public function onController(ControllerEvent $event): void
30+
{
31+
if (!$event->isMainRequest()) {
32+
return;
33+
}
34+
35+
$controller = $event->getController();
36+
if (!\is_array($controller)) {
37+
return;
38+
}
39+
40+
[$controllerObject, $methodName] = $controller;
41+
42+
if ($this->isPublicRoute($controllerObject, $methodName)) {
43+
return;
44+
}
45+
46+
$request = $event->getRequest();
47+
$session = $request->getSession();
48+
49+
if (!$session->has('auth_token')) {
50+
$loginUrl = $this->urlGenerator->generate('login');
51+
$event->setController(static fn () => new RedirectResponse($loginUrl));
52+
}
53+
}
54+
55+
private function isPublicRoute(object $controllerObject, string $methodName): bool
56+
{
57+
$rc = new ReflectionClass($controllerObject);
58+
59+
if ($rc->hasMethod($methodName)) {
60+
$rm = new ReflectionMethod($controllerObject, $methodName);
61+
foreach ($rm->getAttributes(PublicRoute::class) as $attr) {
62+
/** @var PublicRoute $instance */
63+
$instance = $attr->newInstance();
64+
if ($instance->isPublic) {
65+
return true;
66+
}
67+
}
68+
}
69+
70+
foreach ($rc->getAttributes(PublicRoute::class) as $attr) {
71+
/** @var PublicRoute $instance */
72+
$instance = $attr->newInstance();
73+
if ($instance->isPublic) {
74+
return true;
75+
}
76+
}
77+
78+
return false;
79+
}
80+
}

0 commit comments

Comments
 (0)