diff --git a/config/packages/csrf.yaml b/config/packages/csrf.yaml index 40d4040..da56142 100644 --- a/config/packages/csrf.yaml +++ b/config/packages/csrf.yaml @@ -1,11 +1,3 @@ -# Enable stateless CSRF protection for forms and logins/logouts framework: form: - csrf_protection: - token_id: submit - - csrf_protection: - stateless_token_ids: - - submit - - authenticate - - logout + csrf_protection: true diff --git a/src/Controller/SecurityController.php b/src/Controller/SecurityController.php index c5da2b2..7378bfe 100644 --- a/src/Controller/SecurityController.php +++ b/src/Controller/SecurityController.php @@ -4,8 +4,14 @@ declare(strict_types=1); namespace App\Controller; +use App\Entity\User; +use App\Form\RegistrationFormType; +use Doctrine\ORM\EntityManagerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Bundle\SecurityBundle\Security; +use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface; use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Security\Http\Authentication\AuthenticationUtils; @@ -31,9 +37,35 @@ class SecurityController extends AbstractController } #[Route('/register', name: 'app_register', methods: ['GET', 'POST'])] - public function register(): Response - { - // Implemented in Story 1.3 - return $this->render('security/register.html.twig'); + public function register( + Request $request, + UserPasswordHasherInterface $hasher, + EntityManagerInterface $em, + Security $security, + ): Response { + if ($this->getUser()) { + return $this->redirectToRoute('spa'); + } + + $user = new User(); + $form = $this->createForm(RegistrationFormType::class, $user); + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + /** @var string $plainPassword */ + $plainPassword = $form->get('plainPassword')->getData(); + $user->setPassword($hasher->hashPassword($user, $plainPassword)); + + $em->persist($user); + $em->flush(); + + $response = $security->login($user, 'form_login', 'main'); + + return $response ?? $this->redirectToRoute('spa'); + } + + return $this->render('security/register.html.twig', [ + 'form' => $form, + ]); } } diff --git a/src/Entity/User.php b/src/Entity/User.php index 4793b9c..cef6e04 100644 --- a/src/Entity/User.php +++ b/src/Entity/User.php @@ -6,11 +6,13 @@ namespace App\Entity; use App\Repository\UserRepository; use Doctrine\ORM\Mapping as ORM; +use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface; use Symfony\Component\Security\Core\User\UserInterface; #[ORM\Entity(repositoryClass: UserRepository::class)] #[ORM\Table(name: '`user`')] +#[UniqueEntity(fields: ['email'], message: 'An account with this email already exists')] class User implements UserInterface, PasswordAuthenticatedUserInterface { #[ORM\Id] diff --git a/src/Form/RegistrationFormType.php b/src/Form/RegistrationFormType.php new file mode 100644 index 0000000..b5d6772 --- /dev/null +++ b/src/Form/RegistrationFormType.php @@ -0,0 +1,46 @@ +add('email', EmailType::class, [ + 'label' => 'Email address', + 'constraints' => [ + new NotBlank(message: 'Please enter your email address'), + new Email(message: 'Please enter a valid email address'), + ], + ]) + ->add('plainPassword', PasswordType::class, [ + 'label' => 'Password', + 'mapped' => false, + 'constraints' => [ + new NotBlank(message: 'Please enter a password'), + new Length( + min: 8, + minMessage: 'Your password must be at least {{ limit }} characters', + ), + ], + ]); + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults(['data_class' => User::class]); + } +} diff --git a/templates/security/register.html.twig b/templates/security/register.html.twig index 1ddb382..0cdce69 100644 --- a/templates/security/register.html.twig +++ b/templates/security/register.html.twig @@ -4,8 +4,170 @@
Registration — Story 1.3
++ {% for error in form.email.vars.errors %}{{ error.message }}{% endfor %} +
++ {% for error in form.plainPassword.vars.errors %}{{ error.message }}{% endfor %} +
+Already have an account? Sign in
+