Compare commits
2 Commits
adbfe09f01
...
f38c5e4350
Author | SHA1 | Date | |
---|---|---|---|
f38c5e4350 | |||
3ab2ef5a9e |
@ -42,7 +42,6 @@
|
|||||||
"symfony/validator": "7.1.*",
|
"symfony/validator": "7.1.*",
|
||||||
"symfony/web-link": "7.1.*",
|
"symfony/web-link": "7.1.*",
|
||||||
"symfony/yaml": "7.1.*",
|
"symfony/yaml": "7.1.*",
|
||||||
"symfonycasts/verify-email-bundle": "^1.17",
|
|
||||||
"twig/extra-bundle": "^2.12|^3.0",
|
"twig/extra-bundle": "^2.12|^3.0",
|
||||||
"twig/twig": "^2.12|^3.0"
|
"twig/twig": "^2.12|^3.0"
|
||||||
},
|
},
|
||||||
|
48
composer.lock
generated
48
composer.lock
generated
@ -4,7 +4,7 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "fa6b415ac11ece0fbfc562be9a5d1df3",
|
"content-hash": "6a957fcd0a6de48ba22ea99ed82f113f",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "composer/semver",
|
"name": "composer/semver",
|
||||||
@ -7342,52 +7342,6 @@
|
|||||||
],
|
],
|
||||||
"time": "2024-08-12T09:59:40+00:00"
|
"time": "2024-08-12T09:59:40+00:00"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "symfonycasts/verify-email-bundle",
|
|
||||||
"version": "v1.17.0",
|
|
||||||
"source": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/SymfonyCasts/verify-email-bundle.git",
|
|
||||||
"reference": "f72af149070b39ef82a7095074378d0a98b4d2ef"
|
|
||||||
},
|
|
||||||
"dist": {
|
|
||||||
"type": "zip",
|
|
||||||
"url": "https://api.github.com/repos/SymfonyCasts/verify-email-bundle/zipball/f72af149070b39ef82a7095074378d0a98b4d2ef",
|
|
||||||
"reference": "f72af149070b39ef82a7095074378d0a98b4d2ef",
|
|
||||||
"shasum": ""
|
|
||||||
},
|
|
||||||
"require": {
|
|
||||||
"ext-json": "*",
|
|
||||||
"php": ">=8.1",
|
|
||||||
"symfony/config": "^5.4 | ^6.0 | ^7.0",
|
|
||||||
"symfony/dependency-injection": "^5.4 | ^6.0 | ^7.0",
|
|
||||||
"symfony/deprecation-contracts": "^2.2 | ^3.0",
|
|
||||||
"symfony/http-kernel": "^5.4 | ^6.0 | ^7.0",
|
|
||||||
"symfony/routing": "^5.4 | ^6.0 | ^7.0"
|
|
||||||
},
|
|
||||||
"require-dev": {
|
|
||||||
"doctrine/orm": "^2.7",
|
|
||||||
"doctrine/persistence": "^2.0",
|
|
||||||
"symfony/framework-bundle": "^5.4 | ^6.0 | ^7.0",
|
|
||||||
"symfony/phpunit-bridge": "^5.4 | ^6.0 | ^7.0"
|
|
||||||
},
|
|
||||||
"type": "symfony-bundle",
|
|
||||||
"autoload": {
|
|
||||||
"psr-4": {
|
|
||||||
"SymfonyCasts\\Bundle\\VerifyEmail\\": "src/"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
|
||||||
"license": [
|
|
||||||
"MIT"
|
|
||||||
],
|
|
||||||
"description": "Simple, stylish Email Verification for Symfony",
|
|
||||||
"support": {
|
|
||||||
"issues": "https://github.com/SymfonyCasts/verify-email-bundle/issues",
|
|
||||||
"source": "https://github.com/SymfonyCasts/verify-email-bundle/tree/v1.17.0"
|
|
||||||
},
|
|
||||||
"time": "2024-03-17T02:29:53+00:00"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "twig/extra-bundle",
|
"name": "twig/extra-bundle",
|
||||||
"version": "v3.13.0",
|
"version": "v3.13.0",
|
||||||
|
@ -13,5 +13,4 @@ return [
|
|||||||
Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true],
|
Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true],
|
||||||
Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true],
|
Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true],
|
||||||
Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
|
Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
|
||||||
SymfonyCasts\Bundle\VerifyEmail\SymfonyCastsVerifyEmailBundle::class => ['all' => true],
|
|
||||||
];
|
];
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
security:
|
security:
|
||||||
# https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords
|
# https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords
|
||||||
password_hashers:
|
password_hashers:
|
||||||
Symfony\Component\Security\Core\Employee: 'auto'
|
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
|
||||||
# https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider
|
# https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider
|
||||||
providers:
|
providers:
|
||||||
# used to reload user from session & other features (e.g. switch_user)
|
# used to reload user from session & other features (e.g. switch_user)
|
||||||
@ -40,7 +40,7 @@ security:
|
|||||||
# Easy way to control access for large sections of your site
|
# Easy way to control access for large sections of your site
|
||||||
# Note: Only the *first* access control that matches will be used
|
# Note: Only the *first* access control that matches will be used
|
||||||
access_control:
|
access_control:
|
||||||
#- { path: ^/*, roles: ROLE_USER }
|
- { path: ^/*, roles: ROLE_USER }
|
||||||
|
|
||||||
when@test:
|
when@test:
|
||||||
security:
|
security:
|
||||||
|
@ -9,7 +9,7 @@ use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
|
|||||||
|
|
||||||
class DashboardController extends AbstractController
|
class DashboardController extends AbstractController
|
||||||
{
|
{
|
||||||
#[Route(path: '/dashboard', name: 'app_dashboard')]
|
#[Route(path: '/dashboard', name: 'dashboard')]
|
||||||
public function index(): Response
|
public function index(): Response
|
||||||
{
|
{
|
||||||
return $this->render('dashboard/index.html.twig');
|
return $this->render('dashboard/index.html.twig');
|
||||||
|
@ -30,6 +30,11 @@ final class EmployeeController extends AbstractController
|
|||||||
$form->handleRequest($request);
|
$form->handleRequest($request);
|
||||||
|
|
||||||
if ($form->isSubmitted() && $form->isValid()) {
|
if ($form->isSubmitted() && $form->isValid()) {
|
||||||
|
|
||||||
|
$employee->setPassword(
|
||||||
|
password_hash($form->get('plainPassword')->getData(), PASSWORD_BCRYPT)
|
||||||
|
);
|
||||||
|
|
||||||
$entityManager->persist($employee);
|
$entityManager->persist($employee);
|
||||||
$entityManager->flush();
|
$entityManager->flush();
|
||||||
|
|
||||||
|
@ -1,86 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Controller;
|
|
||||||
|
|
||||||
use App\Entity\Employee;
|
|
||||||
use App\Form\RegistrationFormType;
|
|
||||||
use App\Security\EmailVerifier;
|
|
||||||
use App\Security\LoginFormAuthenticator;
|
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
|
||||||
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
|
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
|
||||||
use Symfony\Bundle\SecurityBundle\Security;
|
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
|
||||||
use Symfony\Component\Mime\Address;
|
|
||||||
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
|
|
||||||
use Symfony\Component\Routing\Attribute\Route;
|
|
||||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
|
||||||
use SymfonyCasts\Bundle\VerifyEmail\Exception\VerifyEmailExceptionInterface;
|
|
||||||
|
|
||||||
class RegistrationController extends AbstractController
|
|
||||||
{
|
|
||||||
public function __construct(private EmailVerifier $emailVerifier)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
#[Route('/register', name: 'app_register')]
|
|
||||||
public function register(Request $request, UserPasswordHasherInterface $userPasswordHasher, Security $security, EntityManagerInterface $entityManager): Response
|
|
||||||
{
|
|
||||||
$employee = new Employee();
|
|
||||||
$form = $this->createForm(RegistrationFormType::class, $employee);
|
|
||||||
$form->handleRequest($request);
|
|
||||||
|
|
||||||
if ($form->isSubmitted() && $form->isValid()) {
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// encode the plain password
|
|
||||||
$employee->setPassword(
|
|
||||||
password_hash($form->get('plainPassword')->getData(), PASSWORD_BCRYPT)
|
|
||||||
);
|
|
||||||
|
|
||||||
$entityManager->persist($employee);
|
|
||||||
$entityManager->flush();
|
|
||||||
|
|
||||||
// generate a signed url and email it to the employee
|
|
||||||
$this->emailVerifier->sendEmailConfirmation('app_verify_email', $employee,
|
|
||||||
(new TemplatedEmail())
|
|
||||||
->from(new Address('no-reply@HegreLand.com', 'Hegre Land'))
|
|
||||||
->to((string) $employee->getEmail())
|
|
||||||
->subject('Please Confirm your Email')
|
|
||||||
->htmlTemplate('registration/confirmation_email.html.twig')
|
|
||||||
);
|
|
||||||
|
|
||||||
// do anything else you need here, like send an email
|
|
||||||
|
|
||||||
return $security->login($employee, LoginFormAuthenticator::class, 'main');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->render('registration/register.html.twig', [
|
|
||||||
'registrationForm' => $form,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[Route('/verify/email', name: 'app_verify_email')]
|
|
||||||
public function verifyUserEmail(Request $request, TranslatorInterface $translator): Response
|
|
||||||
{
|
|
||||||
$this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY');
|
|
||||||
|
|
||||||
// validate email confirmation link, sets User::isVerified=true and persists
|
|
||||||
try {
|
|
||||||
/** @var Employee $employee */
|
|
||||||
$employee = $this->getUser();
|
|
||||||
$this->emailVerifier->handleEmailConfirmation($request, $employee);
|
|
||||||
} catch (VerifyEmailExceptionInterface $exception) {
|
|
||||||
$this->addFlash('verify_email_error', $translator->trans($exception->getReason(), [], 'VerifyEmailBundle'));
|
|
||||||
|
|
||||||
return $this->redirectToRoute('DashboardController');
|
|
||||||
}
|
|
||||||
|
|
||||||
// @TODO Change the redirect on success and handle or remove the flash message in your templates
|
|
||||||
$this->addFlash('success', 'Your email address has been verified.');
|
|
||||||
|
|
||||||
return $this->redirectToRoute('app_register');
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,22 +2,26 @@
|
|||||||
|
|
||||||
namespace App\Controller;
|
namespace App\Controller;
|
||||||
|
|
||||||
|
use App\Form\LoginType;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Routing\Attribute\Route;
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
|
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
|
||||||
|
|
||||||
|
#[Route(path: '/login', name: 'security')]
|
||||||
class SecurityController extends AbstractController
|
class SecurityController extends AbstractController
|
||||||
{
|
{
|
||||||
#[Route(path: '/login', name: 'app_login')]
|
#[Route(path: '', name: '_login')]
|
||||||
public function login(AuthenticationUtils $authenticationUtils): Response
|
public function login(AuthenticationUtils $authenticationUtils): Response
|
||||||
{
|
{
|
||||||
// if ($this->getUser()) {
|
// if ($this->getUser()) {
|
||||||
// return $this->redirectToRoute('target_path');
|
// return $this->redirectToRoute('dashboard');
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// get the login error if there is one
|
// get the login error if there is one
|
||||||
$error = $authenticationUtils->getLastAuthenticationError();
|
$error = $authenticationUtils->getLastAuthenticationError();
|
||||||
|
|
||||||
// last username entered by the user
|
// last username entered by the user
|
||||||
$lastUsername = $authenticationUtils->getLastUsername();
|
$lastUsername = $authenticationUtils->getLastUsername();
|
||||||
|
|
||||||
@ -25,7 +29,7 @@ class SecurityController extends AbstractController
|
|||||||
return $this->render('security/login.html.twig', ['last_username' => $lastUsername, 'error' => $error]);
|
return $this->render('security/login.html.twig', ['last_username' => $lastUsername, 'error' => $error]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route(path: '/logout', name: 'app_logout')]
|
#[Route(path: '/logout', name: '_logout')]
|
||||||
public function logout(): void
|
public function logout(): void
|
||||||
{
|
{
|
||||||
throw new \LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.');
|
throw new \LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.');
|
||||||
|
@ -6,16 +6,17 @@ use App\Repository\MissionCategoryRepository;
|
|||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
|
||||||
#[ORM\Entity(repositoryClass: MissionCategoryRepository::class)]
|
#[ORM\Entity(repositoryClass: MissionCategoryRepository::class)]
|
||||||
|
#[ORM\UniqueConstraint(columns: ['mission', 'category'])]
|
||||||
class MissionCategory
|
class MissionCategory
|
||||||
{
|
{
|
||||||
#[ORM\Id]
|
#[ORM\Id]
|
||||||
#[ORM\OneToMany(targetEntity: Mission::class, mappedBy: 'MissionCategory')]
|
#[ORM\ManyToOne(targetEntity: Mission::class, inversedBy: 'missionCategories')]
|
||||||
#[ORM\JoinColumn(nullable: false)]
|
#[ORM\Column(type: 'integer')]
|
||||||
private ?Mission $mission = null;
|
private ?Mission $mission = null;
|
||||||
|
|
||||||
#[ORM\Id]
|
#[ORM\Id]
|
||||||
#[ORM\OneToMany(targetEntity: Category::class, mappedBy: 'MissionCategory')]
|
#[ORM\ManyToOne(targetEntity: Category::class, inversedBy: 'missionCategories')]
|
||||||
#[ORM\JoinColumn(nullable: false)]
|
#[ORM\Column(type: 'integer')]
|
||||||
private ?Category $category = null;
|
private ?Category $category = null;
|
||||||
|
|
||||||
public function getMission(): ?Mission
|
public function getMission(): ?Mission
|
||||||
|
@ -10,6 +10,8 @@ use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
|||||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
use Symfony\Component\Validator\Constraints\Length;
|
||||||
|
use Symfony\Component\Validator\Constraints\NotBlank;
|
||||||
|
|
||||||
class EmployeeType extends AbstractType
|
class EmployeeType extends AbstractType
|
||||||
{
|
{
|
||||||
@ -19,7 +21,6 @@ class EmployeeType extends AbstractType
|
|||||||
->add('email', EmailType::class, ['label' => 'Email Address'])
|
->add('email', EmailType::class, ['label' => 'Email Address'])
|
||||||
->add('firstName', TextType::class, ['label' => 'First Name'])
|
->add('firstName', TextType::class, ['label' => 'First Name'])
|
||||||
->add('lastName', TextType::class, ['label' => 'Last Name'])
|
->add('lastName', TextType::class, ['label' => 'Last Name'])
|
||||||
->add('password', PasswordType::class, ['label' => 'Password'])
|
|
||||||
->add('roles', ChoiceType::class, [
|
->add('roles', ChoiceType::class, [
|
||||||
'label' => 'Roles (comma-separated)',
|
'label' => 'Roles (comma-separated)',
|
||||||
'required' => false,
|
'required' => false,
|
||||||
@ -30,7 +31,23 @@ class EmployeeType extends AbstractType
|
|||||||
'multiple' => true, // Allow multiple selections
|
'multiple' => true, // Allow multiple selections
|
||||||
'expanded' => true, // Render as checkboxes
|
'expanded' => true, // Render as checkboxes
|
||||||
])
|
])
|
||||||
;
|
->add('plainPassword', PasswordType::class, [
|
||||||
|
// instead of being set onto the object directly,
|
||||||
|
// this is read and encoded in the controller
|
||||||
|
'mapped' => false,
|
||||||
|
'attr' => ['autocomplete' => 'new-password'],
|
||||||
|
'constraints' => [
|
||||||
|
new NotBlank([
|
||||||
|
'message' => 'Please enter a password',
|
||||||
|
]),
|
||||||
|
new Length([
|
||||||
|
'min' => 6,
|
||||||
|
'minMessage' => 'Your password should be at least {{ limit }} characters',
|
||||||
|
// max length allowed by Symfony for security reasons
|
||||||
|
'max' => 4096,
|
||||||
|
]),
|
||||||
|
],
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function configureOptions(OptionsResolver $resolver): void
|
public function configureOptions(OptionsResolver $resolver): void
|
||||||
|
@ -1,64 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Form;
|
|
||||||
|
|
||||||
use App\Entity\Employee;
|
|
||||||
use Symfony\Component\Form\AbstractType;
|
|
||||||
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
|
||||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
|
||||||
use Symfony\Component\Form\Extension\Core\Type\EmailType;
|
|
||||||
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
|
|
||||||
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
|
||||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
|
||||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
|
||||||
use Symfony\Component\Validator\Constraints\IsTrue;
|
|
||||||
use Symfony\Component\Validator\Constraints\Length;
|
|
||||||
use Symfony\Component\Validator\Constraints\NotBlank;
|
|
||||||
|
|
||||||
class RegistrationFormType extends AbstractType
|
|
||||||
{
|
|
||||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
|
||||||
{
|
|
||||||
$builder
|
|
||||||
->add('email', EmailType::class, ['label' => 'Email Address'])
|
|
||||||
->add('firstName', TextType::class, ['label' => 'First Name'])
|
|
||||||
->add('lastName', TextType::class, ['label' => 'Last Name'])
|
|
||||||
->add('roles', ChoiceType::class, [
|
|
||||||
'label' => 'Roles (comma-separated)',
|
|
||||||
'required' => false,
|
|
||||||
'choices' => [
|
|
||||||
'User' => 'ROLE_USER',
|
|
||||||
'Admin' => 'ROLE_ADMIN',
|
|
||||||
],
|
|
||||||
'multiple' => true, // Allow multiple selections
|
|
||||||
'expanded' => true, // Render as checkboxes
|
|
||||||
])
|
|
||||||
->add('plainPassword', PasswordType::class, [
|
|
||||||
// instead of being set onto the object directly,
|
|
||||||
// this is read and encoded in the controller
|
|
||||||
'mapped' => false,
|
|
||||||
'attr' => ['autocomplete' => 'new-password'],
|
|
||||||
'constraints' => [
|
|
||||||
new NotBlank([
|
|
||||||
'message' => 'Please enter a password',
|
|
||||||
]),
|
|
||||||
new Length([
|
|
||||||
'min' => 6,
|
|
||||||
'minMessage' => 'Your password should be at least {{ limit }} characters',
|
|
||||||
// max length allowed by Symfony for security reasons
|
|
||||||
'max' => 4096,
|
|
||||||
]),
|
|
||||||
],
|
|
||||||
])
|
|
||||||
->add('save', SubmitType::class, ['label' => 'Add Employee'])
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function configureOptions(OptionsResolver $resolver): void
|
|
||||||
{
|
|
||||||
$resolver->setDefaults([
|
|
||||||
'data_class' => Employee::class,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,60 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Repository;
|
|
||||||
|
|
||||||
use App\Entity\User;
|
|
||||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
|
||||||
use Doctrine\Persistence\ManagerRegistry;
|
|
||||||
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
|
|
||||||
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
|
|
||||||
use Symfony\Component\Security\Core\User\PasswordUpgraderInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @extends ServiceEntityRepository<User>
|
|
||||||
*/
|
|
||||||
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()
|
|
||||||
// ;
|
|
||||||
// }
|
|
||||||
}
|
|
@ -1,52 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Security;
|
|
||||||
|
|
||||||
use App\Entity\Employee;
|
|
||||||
use App\Entity\User;
|
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
|
||||||
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
|
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
|
||||||
use Symfony\Component\Mailer\MailerInterface;
|
|
||||||
use SymfonyCasts\Bundle\VerifyEmail\Exception\VerifyEmailExceptionInterface;
|
|
||||||
use SymfonyCasts\Bundle\VerifyEmail\VerifyEmailHelperInterface;
|
|
||||||
|
|
||||||
class EmailVerifier
|
|
||||||
{
|
|
||||||
public function __construct(
|
|
||||||
private VerifyEmailHelperInterface $verifyEmailHelper,
|
|
||||||
private MailerInterface $mailer,
|
|
||||||
private EntityManagerInterface $entityManager
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public function sendEmailConfirmation(string $verifyEmailRouteName, Employee $employee, TemplatedEmail $email): void
|
|
||||||
{
|
|
||||||
$signatureComponents = $this->verifyEmailHelper->generateSignature(
|
|
||||||
$verifyEmailRouteName,
|
|
||||||
(string) $employee->getId(),
|
|
||||||
(string) $employee->getEmail()
|
|
||||||
);
|
|
||||||
|
|
||||||
$context = $email->getContext();
|
|
||||||
$context['signedUrl'] = $signatureComponents->getSignedUrl();
|
|
||||||
$context['expiresAtMessageKey'] = $signatureComponents->getExpirationMessageKey();
|
|
||||||
$context['expiresAtMessageData'] = $signatureComponents->getExpirationMessageData();
|
|
||||||
|
|
||||||
$email->context($context);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws VerifyEmailExceptionInterface
|
|
||||||
*/
|
|
||||||
public function handleEmailConfirmation(Request $request, Employee $employee): void
|
|
||||||
{
|
|
||||||
$this->verifyEmailHelper->validateEmailConfirmationFromRequest($request, (string) $employee->getId(), (string) $employee->getEmail());
|
|
||||||
|
|
||||||
$employee->setVerified(true);
|
|
||||||
|
|
||||||
$this->entityManager->persist($employee);
|
|
||||||
$this->entityManager->flush();
|
|
||||||
}
|
|
||||||
}
|
|
@ -20,7 +20,7 @@ class LoginFormAuthenticator extends AbstractLoginFormAuthenticator
|
|||||||
{
|
{
|
||||||
use TargetPathTrait;
|
use TargetPathTrait;
|
||||||
|
|
||||||
public const LOGIN_ROUTE = 'app_login';
|
public const LOGIN_ROUTE = 'security_login';
|
||||||
|
|
||||||
public function __construct(private UrlGeneratorInterface $urlGenerator)
|
public function __construct(private UrlGeneratorInterface $urlGenerator)
|
||||||
{
|
{
|
||||||
@ -28,13 +28,13 @@ class LoginFormAuthenticator extends AbstractLoginFormAuthenticator
|
|||||||
|
|
||||||
public function authenticate(Request $request): Passport
|
public function authenticate(Request $request): Passport
|
||||||
{
|
{
|
||||||
$email = $request->getPayload()->getString('email');
|
$email = $request->getPayload()->getString('_username');
|
||||||
|
|
||||||
$request->getSession()->set(SecurityRequestAttributes::LAST_USERNAME, $email);
|
$request->getSession()->set(SecurityRequestAttributes::LAST_USERNAME, $email);
|
||||||
|
|
||||||
return new Passport(
|
return new Passport(
|
||||||
new UserBadge($email),
|
new UserBadge($email),
|
||||||
new PasswordCredentials($request->getPayload()->getString('password')),
|
new PasswordCredentials($request->getPayload()->getString('_password')),
|
||||||
[
|
[
|
||||||
new CsrfTokenBadge('authenticate', $request->getPayload()->getString('_csrf_token')),
|
new CsrfTokenBadge('authenticate', $request->getPayload()->getString('_csrf_token')),
|
||||||
new RememberMeBadge(),
|
new RememberMeBadge(),
|
||||||
@ -44,12 +44,12 @@ class LoginFormAuthenticator extends AbstractLoginFormAuthenticator
|
|||||||
|
|
||||||
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
|
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
|
||||||
{
|
{
|
||||||
if ($targetPath = $this->getTargetPath($request->getSession(), $firewallName)) {
|
/*if ($targetPath = $this->getTargetPath($request->getSession(), $firewallName)) {
|
||||||
return new RedirectResponse($targetPath);
|
return new RedirectResponse($targetPath);
|
||||||
}
|
}*/
|
||||||
|
|
||||||
// For example:
|
// For example:
|
||||||
return new RedirectResponse($this->urlGenerator->generate('app_dashboard'));
|
return new RedirectResponse($this->urlGenerator->generate('dashboard'));
|
||||||
//return new RedirectResponse($this->urlGenerator->generate('DashboardController'));
|
//return new RedirectResponse($this->urlGenerator->generate('DashboardController'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
<h1>Hi! Please confirm your email!</h1>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Please confirm your email address by clicking the following link: <br><br>
|
|
||||||
<a href="{{ signedUrl|raw }}">Confirm my Email</a>.
|
|
||||||
This link will expire in {{ expiresAtMessageKey|trans(expiresAtMessageData, 'VerifyEmailBundle') }}.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Cheers!
|
|
||||||
</p>
|
|
@ -1,32 +0,0 @@
|
|||||||
{% extends 'base.html.twig' %}
|
|
||||||
|
|
||||||
{% block title %}HegreLand{% endblock %}
|
|
||||||
|
|
||||||
{% block body %}
|
|
||||||
{% for flash_error in app.flashes('verify_email_error') %}
|
|
||||||
<div class="alert alert-danger" role="alert">{{ flash_error }}</div>
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
<h1>M'inscrire</h1>
|
|
||||||
|
|
||||||
{{ form_errors(registrationForm) }}
|
|
||||||
|
|
||||||
{{ form_start(registrationForm) }}
|
|
||||||
<div>
|
|
||||||
{{ form_row(registrationForm.email) }}
|
|
||||||
{{ form_row(registrationForm.firstName) }}
|
|
||||||
{{ form_row(registrationForm.lastName) }}
|
|
||||||
{{ form_row(registrationForm.roles) }}
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
{{ form_row(registrationForm.plainPassword, {
|
|
||||||
label: 'Password'
|
|
||||||
}) }}
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button type="submit" class="btn">M'inscrire</button>
|
|
||||||
<p>Déjà inscrit(e) ?<a href="{{ path('app_login') }}"> Me connecter</a> </p>
|
|
||||||
|
|
||||||
{{ form_end(registrationForm) }}
|
|
||||||
{% endblock %}
|
|
@ -3,24 +3,39 @@
|
|||||||
{% block title %}HegreLand{% endblock %}
|
{% block title %}HegreLand{% endblock %}
|
||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
<form method="post">
|
<form method="post">
|
||||||
{% if error %}
|
{% if error %}
|
||||||
<div class="alert alert-danger">{{ error.messageKey|trans(error.messageData, 'security') }}</div>
|
<div class="alert alert-danger">{{ error.messageKey|trans(error.messageData, 'security') }}</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if app.user %}
|
{% if app.user %}
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
Vous êtes déjà connecté(e) en tant que {{ app.user.userIdentifier }}, <a href="{{ path('app_logout') }}">Me déconnecter</a>
|
You are logged in as {{ app.user.userIdentifier }}, <a href="{{ path('security_logout') }}">Logout</a>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<h1 class="h3 mb-3 font-weight-normal">Please sign in</h1>
|
||||||
|
<label for="username">Email</label>
|
||||||
|
<input type="email" value="{{ last_username }}" name="_username" id="username" class="form-control" autocomplete="email" required autofocus>
|
||||||
|
<label for="password">Password</label>
|
||||||
|
<input type="password" name="_password" id="password" class="form-control" autocomplete="current-password" required>
|
||||||
|
|
||||||
|
<input type="hidden" name="_csrf_token"
|
||||||
|
value="{{ csrf_token('authenticate') }}"
|
||||||
|
>
|
||||||
|
|
||||||
|
{#
|
||||||
|
Uncomment this section and add a remember_me option below your firewall to activate remember me functionality.
|
||||||
|
See https://symfony.com/doc/current/security/remember_me.html
|
||||||
|
|
||||||
|
<div class="checkbox mb-3">
|
||||||
|
<input type="checkbox" name="_remember_me" id="_remember_me">
|
||||||
|
<label for="_remember_me">Remember me</label>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
#}
|
||||||
|
|
||||||
|
<button class="btn btn-lg btn-primary" type="submit">
|
||||||
<h1 class="h3 mb-3 font-weight-normal">Me connecter</h1>
|
Sign in
|
||||||
{{ form_row(loginForm.email) }}
|
</button>
|
||||||
<button class="btn btn-lg btn-primary" type="submit">
|
</form>
|
||||||
Se connecter
|
|
||||||
</button>
|
|
||||||
<p><a href="#"> Mot de passe oublié</a> </p>
|
|
||||||
<p>Pas encore inscrit(e) ?<a href="{{ path('app_register') }}"> M'inscrire</a> </p>
|
|
||||||
</form>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user