Skip to content

Commit 785827f

Browse files
committed
New service to simplify password encoding
1 parent 2ae4f34 commit 785827f

File tree

2 files changed

+47
-26
lines changed

2 files changed

+47
-26
lines changed

book/security.rst

+31-4
Original file line numberDiff line numberDiff line change
@@ -1459,30 +1459,57 @@ is available by calling the PHP function :phpfunction:`hash_algos`.
14591459
Determining the Hashed Password
14601460
...............................
14611461

1462+
.. versionadded:: 2.6
1463+
The ``security.password_encoder`` service was introduced in Symfony 2.6.
1464+
14621465
If you're storing users in the database and you have some sort of registration
14631466
form for users, you'll need to be able to determine the hashed password so
14641467
that you can set it on your user before inserting it. No matter what algorithm
14651468
you configure for your user object, the hashed password can always be determined
14661469
in the following way from a controller::
14671470

1468-
$factory = $this->get('security.encoder_factory');
14691471
$user = new Acme\UserBundle\Entity\User();
1472+
$plainPassword = 'ryanpass';
1473+
$encoded = $this->container->get('security.password_encoder')
1474+
->encodePassword($user, $plainPassword);
14701475

1471-
$encoder = $factory->getEncoder($user);
1472-
$password = $encoder->encodePassword('ryanpass', $user->getSalt());
1473-
$user->setPassword($password);
1476+
$user->setPassword($encoded);
14741477

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

1482+
.. sidebar:: Get the User Encoder
1483+
1484+
In some cases, you need a specific encoder for a given user (e.g. ``Acme\UserBundle\Entity\User``).
1485+
You can use the ``EncoderFactory`` to get this encoder::
1486+
1487+
$factory = $this->get('security.encoder_factory');
1488+
$user = new Acme\UserBundle\Entity\User();
1489+
1490+
$encoder = $factory->getEncoder($user);
1491+
14791492
.. caution::
14801493

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

1499+
Validating a Plaintext Password
1500+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1501+
1502+
Sometimes you want to check if a plain password is valid for a given user::
1503+
1504+
// a user instance of some class which implements Symfony\Component\Security\Core\User\UserInterface
1505+
$user = ...;
1506+
1507+
// the password that should be checked
1508+
$plainPassword = ...;
1509+
1510+
$isValidPassword = $this->container->get('security.password_encoder')
1511+
->isPasswordValid($user, $plainPassword);
1512+
14861513
Retrieving the User Object
14871514
~~~~~~~~~~~~~~~~~~~~~~~~~~
14881515

cookbook/security/custom_password_authenticator.rst

+16-22
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)