diff --git a/config/packages/security.yaml b/config/packages/security.yaml index bfc2c7b..087e1fd 100644 --- a/config/packages/security.yaml +++ b/config/packages/security.yaml @@ -2,10 +2,7 @@ security: encoders: App\Entity\User: algorithm: auto - - # https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers providers: - # used to reload user from session & other features (e.g. switch_user) app_user_provider: entity: class: App\Entity\User @@ -16,15 +13,16 @@ security: security: false main: anonymous: lazy - - # activate different ways to authenticate - # https://symfony.com/doc/current/security.html#firewalls-authentication - - # https://symfony.com/doc/current/security/impersonating_user.html - # switch_user: true - - # Easy way to control access for large sections of your site - # Note: Only the *first* access control that matches will be used + remember_me: + secret: '%kernel.secret%' + lifetime: 604800 # 1 week + path: / + secure: true + guard: + authenticators: + - App\Security\LoginFormAuthentificatorAuthenticator + logout: + path: app_security_logout + target: app_external_index access_control: - # - { path: ^/admin, roles: ROLE_ADMIN } - # - { path: ^/profile, roles: ROLE_USER } + - { path: ^/login$, roles: IS_AUTHENTICATED_ANONYMOUSLY } diff --git a/src/Controller/ExternalController.php b/src/Controller/ExternalController.php index c833e25..00c984c 100644 --- a/src/Controller/ExternalController.php +++ b/src/Controller/ExternalController.php @@ -8,9 +8,8 @@ use Symfony\Component\Routing\Annotation\Route; class ExternalController extends AbstractController { /** * @Route("/") - * @Route("/index") */ public function index () { - return $this->render('index.html.twig'); + return $this->render('external/index.html.twig'); } } \ No newline at end of file diff --git a/src/Controller/SecurityController.php b/src/Controller/SecurityController.php new file mode 100644 index 0000000..4291e95 --- /dev/null +++ b/src/Controller/SecurityController.php @@ -0,0 +1,47 @@ +getLastAuthenticationError(); + $lastUsername = $authenticationUtils->getLastUsername(); + + return $this->render('security/login.html.twig', [ + 'last_username' => $lastUsername, + 'error' => $error, + ] + ); + } + + /** + * *Perform* logout + * + * @throws Exception When firewall failed and this method is *really* called + * + * @Route("/logout") + */ + public function logout () { + throw new Exception('This method can be blank - it will be intercepted by the logout key on your firewall'); + } +} diff --git a/src/Security/LoginFormAuthentificatorAuthenticator.php b/src/Security/LoginFormAuthentificatorAuthenticator.php new file mode 100644 index 0000000..6302519 --- /dev/null +++ b/src/Security/LoginFormAuthentificatorAuthenticator.php @@ -0,0 +1,99 @@ +entityManager = $entityManager; + $this->urlGenerator = $urlGenerator; + $this->csrfTokenManager = $csrfTokenManager; + $this->passwordEncoder = $passwordEncoder; + } + + public function supports (Request $request) { + return 'app_security_login' === $request->attributes->get('_route') && $request->isMethod('POST'); + } + + public function getCredentials (Request $request) { + $credentials = [ + 'email' => $request->request->get('email'), + 'password' => $request->request->get('password'), + 'csrf_token' => $request->request->get('_csrf_token'), + ]; + $request->getSession()->set( + Security::LAST_USERNAME, + $credentials['email'] + ); + + return $credentials; + } + + public function getUser ($credentials, UserProviderInterface $userProvider) { + $token = new CsrfToken('authenticate', $credentials['csrf_token']); + if (!$this->csrfTokenManager->isTokenValid($token)) { + throw new InvalidCsrfTokenException(); + } + + $user = $this->entityManager->getRepository(User::class)->findOneBy(['email' => $credentials['email']]); + + if (!$user) { + // fail authentication with a custom error + throw new CustomUserMessageAuthenticationException('Email could not be found.'); + } + + return $user; + } + + public function checkCredentials ($credentials, UserInterface $user) { + return $this->passwordEncoder->isPasswordValid($user, $credentials['password']); + } + + /** + * Used to upgrade (rehash) the user's password automatically over time. + */ + public function getPassword ($credentials): ?string { + return $credentials['password']; + } + + public function onAuthenticationSuccess (Request $request, TokenInterface $token, $providerKey) { + if ($targetPath = $this->getTargetPath($request->getSession(), $providerKey)) { + return new RedirectResponse($targetPath); + } + + return new RedirectResponse($this->urlGenerator->generate('app_external_index')); + } + + protected function getLoginUrl () { + return $this->urlGenerator->generate('app_security_login'); + } +} diff --git a/templates/base.html.twig b/templates/base.html.twig index 14b3759..8cb3377 100644 --- a/templates/base.html.twig +++ b/templates/base.html.twig @@ -2,7 +2,7 @@
-diff --git a/templates/security/login.html.twig b/templates/security/login.html.twig new file mode 100644 index 0000000..9ed6fdc --- /dev/null +++ b/templates/security/login.html.twig @@ -0,0 +1,35 @@ +{% extends 'base.html.twig' %} + +{% block title %}Log in{% endblock %} + +{% block body %} +
+{% endblock %}