Infos : I'm new to Symfony and Sonata
My objective : Encrypte the password only for the database side. I would be able to display this password in clear. All this for the field password in the entity Service.
What did i'm trying ? : I tryed to create a Doctrine Listener which use bcrypt
encryption
security:
encoders: App\Entity\Service: bcrypt
here is the HashPasswordLisetener.php in my App\Doctrine (in the $formMapper of my configureFormField function in App\Admin\ServiceAdmin.php i have a row like this ->add('password')
)
<?php
namespace App\Doctrine;
use App\Entity\Service;
use Doctrine\Common\EventSubscriber;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
class HashPasswordListener implements EventSubscriber
{
private $passwordEncoder;
public function __construct(UserPasswordEncoderInterface $passwordEncoder)
{
$this->passwordEncoder = $passwordEncoder;
}
public function prePersist(LifecycleEventArgs $args)
{
$entity = $args->getEntity();
if (!$entity instanceof Service) {
return;
}
$this->encodePassword($entity);
}
public function preUpdate(LifecycleEventArgs $args)
{
$entity = $args->getEntity();
if (!$entity instanceof Service) {
return;
}
$this->encodePassword($entity);
$em = $args->getEntityManager();
$meta = $em->getClassMetadata(get_class($entity));
$em->getUnitOfWork()->recomputeSingleEntityChangeSet($meta, $entity);
}
public function getSubscribedEvents()
{
return ['prePersist', 'preUpdate'];
}
/**
* @param Service $entity
*/
private function encodePassword(Service $entity)
{
if (!$entity->getPlainPassword()) {
return;
}
$encoded = $this->passwordEncoder->encodePassword(
$entity,
$entity->getPlainPassword()
);
$entity->setPassword($encoded);
}
}
here is the Service entity in the App\Entity
<?php
namespace App\Entity;
use App\Admin\AbstractAdmin;
use App\Repository\ServiceRepository;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Timestampable\Traits\TimestampableEntity;
use Symfony\Component\Security\Core\User\UserInterface;
/**
* @ORM\Entity(repositoryClass=ServiceRepository::class)
*/
class Service implements UserInterface
{
use TimestampableEntity;
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=255)
*/
private $name;
/**
* @ORM\Column(type="string", length=255)
*/
private $password;
/**
* @ORM\Column(type="text", nullable=true, length=255)
*/
private $comment;
/**
* @ORM\Column(type="string", length=255)
*/
private $identifier;
private $plainPassword;
public function getId(): ?int
{
return $this->id;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
public function getPassword(): ?string
{
return $this->password;
}
public function setPassword(string $password): self
{
$this->password = $password;
return $this;
}
public function getComment(): ?string
{
return $this->comment;
}
public function setComment(?string $comment): self
{
$this->comment = $comment;
return $this;
}
public function getIdentifier(): ?string
{
return $this->identifier;
}
public function setIdentifier(string $identifier): self
{
$this->identifier = $identifier;
return $this;
}
/**
* @return mixed
*/
public function getPlainPassword()
{
return $this->plainPassword;
}
/**
* @param mixed $plainPassword
*/
public function setPlainPassword($plainPassword): void
{
$this->plainPassword = $plainPassword;
$this->password = null;
}
public function getRoles()
{
return array('ROLE_USER');
}
public function getSalt()
{
}
public function eraseCredentials()
{
$this->plainPassword = null;
}
public function getUsername()
{
return $this->identifier;
}
}
Also my sonata_admin.yaml :
app.doctrine.hash_password_listener:
class: App\Doctrine\HashPasswordListener
autowire : true
tags:
- { name: doctrine.event_subscriber, connection: 'default' }
My Probleme : I understand the function encodePassword is waiting for a UserInterface in 1st arg (instead of my entity) and the password to encrypt in 2nd arg but i don't understand who use this UserInterface ? Where i'm suppose to call it ? to get it ? to send it ?
I think i give lot of details but if i forgot something feel free to notice me ^^ Thanks the time you spend at least reading.
I had a probleme but i was coding an Hashing type of code but i was looking for an encrypting methode. but here is how i deal for having a working hashing :
Step 1 : implementing UserInterface in my Service entity
Step 2 : Replace UserPasswordEncoder for UserPasswordEncoderInterface in the Listener
Step 2.5 : Added all function needed for the UserInterface
like eraseCredidential
getSalt()
.. see : this for more details
Step 3 : Adding a getUsername
which return this->identifier
Step 4 : using plainPasswords
in form field instead of password
Step 5 : added a provider :
app_user:
entity:
class: 'App\Entity\Service'
property: 'identifier'
Step 6 : Using TextType::class
for plainPassword
form field type + fixing the use
with :
Symfony\Component\Form\Extension\Core\Type\TextType
Step 7 : Working
(Special thanks to @msg who helped me a lot)