How to use encoder factory in Symfony 2 inside the

2020-07-16 03:28发布

问题:

This question about Symfony 2.1

How can I encode User password with:

$factory = $this->get('security.encoder_factory');
$user = new Acme\UserBundle\Entity\User();

$encoder = $factory->getEncoder($user);
$password = $encoder->encodePassword('ryanpass', $user->getSalt());
$user->setPassword($password);

And base config:

# app/config/security.yml
security:
    # ...

    encoders:
        Acme\UserBundle\Entity\User: sha512

Inside the setter models:

class User implements UserInterface, \Serializable
{
    public function setPassword($password)
    {
       $this->password = $password;
    }
}

I believe that the process of encryption password must deal by model. How can I use standart encoder factory inside the model?

回答1:

The entity contains data, not handles it. If you want to change data of an entity you can create the event listener and do stuff before persistence. Check How to Register Event Listeners and Subscribers from the official documentation.

You can also take a look at FosUserBundle and its user management.

FosUserBundle UserManager

So, the main idea is to pass plain password from a form to the user entity and encode it before persitence using event listener.



回答2:

While I agree with @Vadim that you shouldn't be leaking business logic into your model, I would be careful with deferring the hashing of the plaintext password until the prePersist event, for example, unless you call persist and flush right after setPassword. A getPassword call in the meantime will return the plaintext string unless you have stored it in a separate field, which could have serious consequences. Ideally the plaintext password should exist for as short a time as possible within the application's lifecycle.

I recommend using a service layer wherein a "User Manager" provides an interface to common tasks, so that you don't need to pollute your password property even temporarily:

class UserManager
{
    // ...
    public function __construct(EncoderFactoryInterface $encoderFactory)
    {
        // $encoderFactory is injected by the DIC as requested by your service configuration
        // ...
    }

    public function setUserPassword(UserInterface $user, $plaintextPassword)
    {
        $hash = $this->encoderFactory->getEncoder($user)->encodePassword($plaintextPassword, null);
        $user->setPassword($hash);
    }
    // ...
}

In your controller for registration form submission, for instance:

public function userRegistrationAction()
{
    // ... 
    if ($form->isValid()) {
        $user = new User();
        // ...
        $this->get('my.bundle.user_manager')->setUserPassword($user, $form->get('password')->getData());
        // ...
    }
}