From 8c1ad80c3b03e03be1831e2125328f6fd32d990d Mon Sep 17 00:00:00 2001 From: bourgoino Date: Thu, 3 Oct 2024 16:54:08 +0200 Subject: [PATCH] appelle le comme tu veux --- .gitignore | 1 + config/packages/security.yaml | 21 +++- src/Controller/SecurityController.php | 32 ++++++ src/Entity/User.php | 101 ++++++++++++++++++ src/Repository/UserRepository.php | 60 +++++++++++ .../UsersAuthentificatorAuthenticator.php | 60 +++++++++++ templates/security/login.html.twig | 37 +++++++ 7 files changed, 310 insertions(+), 2 deletions(-) create mode 100644 src/Controller/SecurityController.php create mode 100644 src/Entity/User.php create mode 100644 src/Repository/UserRepository.php create mode 100644 src/Security/UsersAuthentificatorAuthenticator.php create mode 100644 templates/security/login.html.twig diff --git a/.gitignore b/.gitignore index 4daae38..f435bc4 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ /public/bundles/ /var/ /vendor/ +/.idea ###< symfony/framework-bundle ### ###> phpunit/phpunit ### diff --git a/config/packages/security.yaml b/config/packages/security.yaml index 367af25..f5049ed 100644 --- a/config/packages/security.yaml +++ b/config/packages/security.yaml @@ -4,14 +4,31 @@ security: Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto' # https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider providers: - users_in_memory: { memory: null } + # used to reload user from session & other features (e.g. switch_user) + app_user_provider: + entity: + class: App\Entity\User + property: id firewalls: dev: pattern: ^/(_(profiler|wdt)|css|images|js)/ security: false main: lazy: true - provider: users_in_memory + provider: app_user_provider + custom_authenticator: App\Security\UsersAuthentificatorAuthenticator + logout: + path: app_logout + # where to redirect after logout + # target: app_any_route + + remember_me: + secret: '%kernel.secret%' + lifetime: 604800 + path: / + # by default, the feature is enabled by checking a checkbox in the + # login form, uncomment the following line to always enable it. + #always_remember_me: true # activate different ways to authenticate # https://symfony.com/doc/current/security.html#the-firewall diff --git a/src/Controller/SecurityController.php b/src/Controller/SecurityController.php new file mode 100644 index 0000000..2133610 --- /dev/null +++ b/src/Controller/SecurityController.php @@ -0,0 +1,32 @@ +getUser()) { + // return $this->redirectToRoute('target_path'); + // } + + // get the login error if there is one + $error = $authenticationUtils->getLastAuthenticationError(); + // last username entered by the user + $lastUsername = $authenticationUtils->getLastUsername(); + + return $this->render('security/login.html.twig', ['last_username' => $lastUsername, 'error' => $error]); + } + + #[Route(path: '/logout', name: 'app_logout')] + public function logout(): void + { + throw new \LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.'); + } +} diff --git a/src/Entity/User.php b/src/Entity/User.php new file mode 100644 index 0000000..8d1caaf --- /dev/null +++ b/src/Entity/User.php @@ -0,0 +1,101 @@ + The user roles + */ + #[ORM\Column] + private array $roles = []; + + /** + * @var string The hashed password + */ + #[ORM\Column] + private ?string $password = null; + + public function getId(): ?string + { + return $this->id; + } + + public function setId(string $id): static + { + $this->id = $id; + + return $this; + } + + /** + * A visual identifier that represents this user. + * + * @see UserInterface + */ + public function getUserIdentifier(): string + { + return (string) $this->id; + } + + /** + * @see UserInterface + * + * @return list + */ + public function getRoles(): array + { + $roles = $this->roles; + // guarantee every user at least has ROLE_USER + $roles[] = 'ROLE_USER'; + + return array_unique($roles); + } + + /** + * @param list $roles + */ + public function setRoles(array $roles): static + { + $this->roles = $roles; + + return $this; + } + + /** + * @see PasswordAuthenticatedUserInterface + */ + public function getPassword(): ?string + { + return $this->password; + } + + public function setPassword(string $password): static + { + $this->password = $password; + + return $this; + } + + /** + * @see UserInterface + */ + public function eraseCredentials(): void + { + // If you store any temporary, sensitive data on the user, clear it here + // $this->plainPassword = null; + } +} diff --git a/src/Repository/UserRepository.php b/src/Repository/UserRepository.php new file mode 100644 index 0000000..4f2804e --- /dev/null +++ b/src/Repository/UserRepository.php @@ -0,0 +1,60 @@ + + */ +class UserRepository extends ServiceEntityRepository implements PasswordUpgraderInterface +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, User::class); + } + + /** + * Used to upgrade (rehash) the user's password automatically over time. + */ + public function upgradePassword(PasswordAuthenticatedUserInterface $user, string $newHashedPassword): void + { + if (!$user instanceof User) { + throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', $user::class)); + } + + $user->setPassword($newHashedPassword); + $this->getEntityManager()->persist($user); + $this->getEntityManager()->flush(); + } + + // /** + // * @return User[] Returns an array of User objects + // */ + // public function findByExampleField($value): array + // { + // return $this->createQueryBuilder('u') + // ->andWhere('u.exampleField = :val') + // ->setParameter('val', $value) + // ->orderBy('u.id', 'ASC') + // ->setMaxResults(10) + // ->getQuery() + // ->getResult() + // ; + // } + + // public function findOneBySomeField($value): ?User + // { + // return $this->createQueryBuilder('u') + // ->andWhere('u.exampleField = :val') + // ->setParameter('val', $value) + // ->getQuery() + // ->getOneOrNullResult() + // ; + // } +} diff --git a/src/Security/UsersAuthentificatorAuthenticator.php b/src/Security/UsersAuthentificatorAuthenticator.php new file mode 100644 index 0000000..453f382 --- /dev/null +++ b/src/Security/UsersAuthentificatorAuthenticator.php @@ -0,0 +1,60 @@ +getPayload()->getString('id'); + + $request->getSession()->set(SecurityRequestAttributes::LAST_USERNAME, $id); + + return new Passport( + new UserBadge($id), + new PasswordCredentials($request->getPayload()->getString('password')), + [ + new CsrfTokenBadge('authenticate', $request->getPayload()->getString('_csrf_token')), + new RememberMeBadge(), + ] + ); + } + + public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response + { + if ($targetPath = $this->getTargetPath($request->getSession(), $firewallName)) { + return new RedirectResponse($targetPath); + } + + // For example: + // return new RedirectResponse($this->urlGenerator->generate('some_route')); + throw new \Exception('TODO: provide a valid redirect inside '.__FILE__); + } + + protected function getLoginUrl(Request $request): string + { + return $this->urlGenerator->generate(self::LOGIN_ROUTE); + } +} diff --git a/templates/security/login.html.twig b/templates/security/login.html.twig new file mode 100644 index 0000000..2b31be6 --- /dev/null +++ b/templates/security/login.html.twig @@ -0,0 +1,37 @@ +{% extends 'base.html.twig' %} + +{% block title %}Log in!{% endblock %} + +{% block body %} +
+ {% if error %} +
{{ error.messageKey|trans(error.messageData, 'security') }}
+ {% endif %} + + {% if app.user %} +
+ You are logged in as {{ app.user.userIdentifier }}, Logout +
+ {% endif %} + +

Please sign in

+ + + + + + + +
+ +
+ + +
+{% endblock %}