Skip to content

Commit 9de96e6

Browse files
committed
feature #3995 [DX] New service to simplify password encoding (aferrandini)
This PR was merged into the master branch. Discussion ---------- [DX] New service to simplify password encoding | Q | A | ------------- | --- | Doc fix? | no | New docs? | [#11306](symfony/symfony#11306) | Applies to | 2.6 Add documentation for symfony/symfony PR [#11306](symfony/symfony#11306) New service to simplify password encoding. Commits ------- 785827f New service to simplify password encoding
2 parents 928a579 + 785827f commit 9de96e6

File tree

2 files changed

+47
-26
lines changed

2 files changed

+47
-26
lines changed

book/security.rst

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1567,30 +1567,57 @@ is available by calling the PHP function :phpfunction:`hash_algos`.
15671567
Determining the Hashed Password
15681568
...............................
15691569

1570+
.. versionadded:: 2.6
1571+
The ``security.password_encoder`` service was introduced in Symfony 2.6.
1572+
15701573
If you're storing users in the database and you have some sort of registration
15711574
form for users, you'll need to be able to determine the hashed password so
15721575
that you can set it on your user before inserting it. No matter what algorithm
15731576
you configure for your user object, the hashed password can always be determined
15741577
in the following way from a controller::
15751578

1576-
$factory = $this->get('security.encoder_factory');
15771579
$user = new Acme\UserBundle\Entity\User();
1580+
$plainPassword = 'ryanpass';
1581+
$encoded = $this->container->get('security.password_encoder')
1582+
->encodePassword($user, $plainPassword);
15781583

1579-
$encoder = $factory->getEncoder($user);
1580-
$password = $encoder->encodePassword('ryanpass', $user->getSalt());
1581-
$user->setPassword($password);
1584+
$user->setPassword($encoded);
15821585

15831586
In order for this to work, just make sure that you have the encoder for your
15841587
user class (e.g. ``Acme\UserBundle\Entity\User``) configured under the ``encoders``
15851588
key in ``app/config/security.yml``.
15861589

1590+
.. sidebar:: Get the User Encoder
1591+
1592+
In some cases, you need a specific encoder for a given user (e.g. ``Acme\UserBundle\Entity\User``).
1593+
You can use the ``EncoderFactory`` to get this encoder::
1594+
1595+
$factory = $this->get('security.encoder_factory');
1596+
$user = new Acme\UserBundle\Entity\User();
1597+
1598+
$encoder = $factory->getEncoder($user);
1599+
15871600
.. caution::
15881601

15891602
When you allow a user to submit a plaintext password (e.g. registration
15901603
form, change password form), you *must* have validation that guarantees
15911604
that the password is 4096 characters or less. Read more details in
15921605
:ref:`How to implement a simple Registration Form <cookbook-registration-password-max>`.
15931606

1607+
Validating a Plaintext Password
1608+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1609+
1610+
Sometimes you want to check if a plain password is valid for a given user::
1611+
1612+
// a user instance of some class which implements Symfony\Component\Security\Core\User\UserInterface
1613+
$user = ...;
1614+
1615+
// the password that should be checked
1616+
$plainPassword = ...;
1617+
1618+
$isValidPassword = $this->container->get('security.password_encoder')
1619+
->isPasswordValid($user, $plainPassword);
1620+
15941621
Retrieving the User Object
15951622
~~~~~~~~~~~~~~~~~~~~~~~~~~
15961623

cookbook/security/custom_password_authenticator.rst

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,17 @@ Imagine you want to allow access to your website only between 2pm and 4pm
88
UTC. Before Symfony 2.4, you had to create a custom token, factory, listener
99
and provider. In this entry, you'll learn how to do this for a login form
1010
(i.e. where your user submits their username and password).
11+
Before Symfony 2.6, you had to use the password encoder to authenticate the user password.
1112

1213
The Password Authenticator
1314
--------------------------
1415

1516
.. versionadded:: 2.4
1617
The ``SimpleFormAuthenticatorInterface`` interface was introduced in Symfony 2.4.
1718

19+
.. versionadded:: 2.6
20+
The ``UserPasswordEncoderInterface`` interface was introduced in Symfony 2.6.
21+
1822
First, create a new class that implements
1923
:class:`Symfony\\Component\\Security\\Core\\Authentication\\SimpleFormAuthenticatorInterface`.
2024
Eventually, this will allow you to create custom logic for authenticating
@@ -27,18 +31,18 @@ the user::
2731
use Symfony\Component\Security\Core\Authentication\SimpleFormAuthenticatorInterface;
2832
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
2933
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
30-
use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface;
34+
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
3135
use Symfony\Component\Security\Core\Exception\AuthenticationException;
3236
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
3337
use Symfony\Component\Security\Core\User\UserProviderInterface;
3438

3539
class TimeAuthenticator implements SimpleFormAuthenticatorInterface
3640
{
37-
private $encoderFactory;
41+
private $encoder;
3842

39-
public function __construct(EncoderFactoryInterface $encoderFactory)
43+
public function __construct(UserPasswordEncoderInterface $encoder)
4044
{
41-
$this->encoderFactory = $encoderFactory;
45+
$this->encoder = $encoder;
4246
}
4347

4448
public function authenticateToken(TokenInterface $token, UserProviderInterface $userProvider, $providerKey)
@@ -49,12 +53,7 @@ the user::
4953
throw new AuthenticationException('Invalid username or password');
5054
}
5155

52-
$encoder = $this->encoderFactory->getEncoder($user);
53-
$passwordValid = $encoder->isPasswordValid(
54-
$user->getPassword(),
55-
$token->getCredentials(),
56-
$user->getSalt()
57-
);
56+
$passwordValid = $this->encoder->isPasswordValid($user, $token->getCredentials());
5857

5958
if ($passwordValid) {
6059
$currentHour = date('G');
@@ -127,17 +126,12 @@ Ultimately, your job is to return a *new* token object that is "authenticated"
127126
(i.e. it has at least 1 role set on it) and which has the ``User`` object
128127
inside of it.
129128

130-
Inside this method, an encoder is needed to check the password's validity::
129+
Inside this method, the password encoder is needed to check the password's validity::
131130

132-
$encoder = $this->encoderFactory->getEncoder($user);
133-
$passwordValid = $encoder->isPasswordValid(
134-
$user->getPassword(),
135-
$token->getCredentials(),
136-
$user->getSalt()
137-
);
131+
$passwordValid = $this->encoder->isPasswordValid($user, $token->getCredentials());
138132

139-
This is a service that is already available in Symfony and the password algorithm
140-
is configured in the security configuration (e.g. ``security.yml``) under
133+
This is a service that is already available in Symfony and it uses the password algorithm
134+
that is configured in the security configuration (e.g. ``security.yml``) under
141135
the ``encoders`` key. Below, you'll see how to inject that into the ``TimeAuthenticator``.
142136

143137
.. _cookbook-security-password-authenticator-config:
@@ -157,7 +151,7 @@ Now, configure your ``TimeAuthenticator`` as a service:
157151
158152
time_authenticator:
159153
class: Acme\HelloBundle\Security\TimeAuthenticator
160-
arguments: ["@security.encoder_factory"]
154+
arguments: ["@security.password_encoder"]
161155
162156
.. code-block:: xml
163157
@@ -173,7 +167,7 @@ Now, configure your ``TimeAuthenticator`` as a service:
173167
<service id="time_authenticator"
174168
class="Acme\HelloBundle\Security\TimeAuthenticator"
175169
>
176-
<argument type="service" id="security.encoder_factory" />
170+
<argument type="service" id="security.password_encoder" />
177171
</service>
178172
</services>
179173
</container>
@@ -188,7 +182,7 @@ Now, configure your ``TimeAuthenticator`` as a service:
188182
189183
$container->setDefinition('time_authenticator', new Definition(
190184
'Acme\HelloBundle\Security\TimeAuthenticator',
191-
array(new Reference('security.encoder_factory'))
185+
array(new Reference('security.password_encoder'))
192186
));
193187
194188
Then, activate it in the ``firewalls`` section of the security configuration

0 commit comments

Comments
 (0)