User management - Login and user password hash.

This commit is contained in:
2024-04-26 21:37:39 +02:00
parent 30773d7af4
commit 84d9c81afd
7 changed files with 230 additions and 8 deletions
+50 -7
View File
@@ -2,18 +2,25 @@
namespace App\Controller\Admin;
use Doctrine\ORM\EntityManagerInterface;
use App\Entity\User;
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
use EasyCorp\Bundle\EasyAdminBundle\Field\Field;
use EasyCorp\Bundle\EasyAdminBundle\Event\BeforeEntityPersistedEvent;
use Doctrine\ORM\EntityManagerInterface;
use EasyCorp\Bundle\EasyAdminBundle\Field\ChoiceField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
use EasyCorp\Bundle\EasyAdminBundle\Field\Field;
use EasyCorp\Bundle\EasyAdminBundle\Field\FormField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
class UserCrudController extends AbstractCrudController
{
public function __construct(
public UserPasswordHasherInterface $userPasswordHasher
) {}
public static function getEntityFqcn(): string
{
return User::class;
@@ -29,9 +36,12 @@ class UserCrudController extends AbstractCrudController
->setChoices($availableRoles)
->allowMultipleChoices(true);
yield FormField::addPanel('Change password')->setIcon('fa fa-key');
yield Field::new ('password', 'New password')->onlyWhenCreating()->setRequired(true)
yield FormField::addPanel('Set password')->setIcon('fa fa-key');
$fieldPassword = Field::new ('plainPassword', 'New password')
->hideOnIndex()
->setRequired(false)
->setFormType(RepeatedType::class)
->setFormTypeOptions([
'type' => PasswordType::class,
@@ -40,8 +50,41 @@ class UserCrudController extends AbstractCrudController
'error_bubbling' => true,
'invalid_message' => 'The password fields do not match.',
]);
if($pageName == Crud::PAGE_NEW) {
$fieldPassword->setRequired(true);
}
//TODO: Allow password change on Update.
yield $fieldPassword;
}
/**
* @param User $entityInstance
*/
public function persistEntity(EntityManagerInterface $entityManager, $entityInstance): void
{
//Hash password on creation.
$plaintextPassword = $entityInstance->getPlainPassword();
$hashedPassword = $this->userPasswordHasher->hashPassword($entityInstance, $plaintextPassword);
$entityInstance->setPassword($hashedPassword);
parent::updateEntity($entityManager, $entityInstance);
}
/**
* @param User $entityInstance
*/
public function updateEntity(EntityManagerInterface $entityManager, $entityInstance): void
{
$plaintextPassword = $entityInstance->getPlainPassword();
if($plaintextPassword && $plaintextPassword != "") {
//New password set. Hash password.
$hashedPassword = $this->userPasswordHasher->hashPassword($entityInstance, $plaintextPassword);
$entityInstance->setPassword($hashedPassword);
}
parent::updateEntity($entityManager, $entityInstance);
}
}
+58
View File
@@ -0,0 +1,58 @@
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Doctrine\ORM\EntityManagerInterface;
use App\Entity\User;
use App\Repository\UserRepository;
class SecurityController extends AbstractController
{
#[Route(path: '/login', name: 'app_login')]
public function login(AuthenticationUtils $authenticationUtils): Response
{
// 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.');
}
#[Route(path: '/addAdmin', name: 'app_security_addAdmin')]
public function addAdmin(UserPasswordHasherInterface $passwordHasher, EntityManagerInterface $entityManager): Response
{
$user = new User();
$user->setUsername("admin");
$user->setRoles(["ROLE_USER", "ROLE_ADMIN"]);
$plaintextPassword = "admin";
// hash the password (based on the security.yaml config for the $user class)
$hashedPassword = $passwordHasher->hashPassword(
$user,
$plaintextPassword
);
$user->setPassword($hashedPassword);
$entityManager->persist($user);
$entityManager->flush();
return new Response("Created user - Admin");
}
}
+18
View File
@@ -32,6 +32,11 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
#[ORM\Column]
private ?string $password = null;
/**
* @var string Store unhashed user password on user creation/edit.
*/
private ?string $plainPassword = null;
public function getId(): ?int
{
return $this->id;
@@ -98,6 +103,19 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
return $this;
}
public function getPlainPassword(): string
{
return $this->plainPassword;
}
public function setPlainPassword(string $plainPassword): static
{
$this->plainPassword = $plainPassword;
return $this;
}
/**
* @see UserInterface
*/