Skip to content

Commit 0e6cc4d

Browse files
committed
[#3356] Moving serialize and Equatable logic further down for clarity
1 parent dfa761b commit 0e6cc4d

File tree

1 file changed

+54
-35
lines changed

1 file changed

+54
-35
lines changed

cookbook/security/entity_provider.rst

Lines changed: 54 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ The Data Model
3232
--------------
3333

3434
For the purpose of this cookbook, the ``AcmeUserBundle`` bundle contains a
35-
``User`` entity class with the following fields: ``id``, ``username``, ``salt``,
35+
``User`` entity class with the following fields: ``id``, ``username``,
3636
``password``, ``email`` and ``isActive``. The ``isActive`` field tells whether
3737
or not the user account is active.
3838

@@ -77,11 +77,6 @@ focus on the most important methods that come from the
7777
*/
7878
private $username;
7979
80-
/**
81-
* @ORM\Column(type="string", length=32)
82-
*/
83-
private $salt;
84-
8580
/**
8681
* @ORM\Column(type="string", length=64)
8782
*/
@@ -100,7 +95,6 @@ focus on the most important methods that come from the
10095
public function __construct()
10196
{
10297
$this->isActive = true;
103-
$this->salt = md5(uniqid(null, true));
10498
}
10599
106100
/**
@@ -116,7 +110,7 @@ focus on the most important methods that come from the
116110
*/
117111
public function getSalt()
118112
{
119-
return $this->salt;
113+
return null;
120114
}
121115
122116
/**
@@ -192,33 +186,15 @@ interface forces the class to implement the five following methods:
192186

193187
* ``getRoles()``,
194188
* ``getPassword()``,
195-
* ``getSalt()``,
189+
* ``getPassword()``,
196190
* ``getUsername()``,
197191
* ``eraseCredentials()``
198192

199193
For more details on each of these, see :class:`Symfony\\Component\\Security\\Core\\User\\UserInterface`.
200194

201-
.. sidebar:: What is the importance of serialize and unserialize?
202-
203-
The :phpclass:`Serializable` interface and its ``serialize`` and ``unserialize``
204-
methods have been added to allow the ``User`` class to be serialized
205-
to the session. This may or may not be needed depending on your setup,
206-
but it's probably a good idea. The ``id`` is the most important value
207-
that needs to be serialized because the
208-
:method:`Symfony\\Bridge\\Doctrine\\Security\\User\\EntityUserProvider::refreshUser`
209-
method reloads the user on each request by using the ``id``. In practice,
210-
this means that the User object is reloaded from the database on each
211-
request using the ``id`` from the serialized object. This makes sure
212-
all of the User's data is fresh.
213-
214-
Symfony also uses the ``username``, ``salt``, and ``password`` to verify
215-
that the User has not changed between requests. Failing to serialize
216-
these may cause you to be logged out on each request. If your User implements
217-
:class:`Symfony\\Component\\Security\\Core\\User\\EquatableInterface`,
218-
then instead of these properties being checked, your ``isEqualTo`` method
219-
is simply called, and you can check whatever properties you want. Unless
220-
you understand this, you probably *won't* need to implement this interface
221-
or worry about it.
195+
If you're curious about the ``serialize`` method or are looking for details
196+
on the logic of seeing if the User stored in the session is the same as the
197+
one stored in the database, see :ref:`cookbook-security-serialize-equatable`.
222198

223199
Below is an export of the ``User`` table from MySQL with user ``admin`` and
224200
password ``admin`` (which has been encoded). For details on how to create
@@ -227,11 +203,11 @@ user records and encode their password, see :ref:`book-security-encoding-user-pa
227203
.. code-block:: bash
228204
229205
$ mysql> select * from acme_users;
230-
+----+----------+------+------------------------------------------+--------------------+-----------+
231-
| id | username | salt | password | email | is_active |
232-
+----+----------+------+------------------------------------------+--------------------+-----------+
233-
| 1 | admin | | d033e22ae348aeb5660fc2140aec35850c4da997 | admin@example.com | 1 |
234-
+----+----------+------+------------------------------------------+--------------------+-----------+
206+
+----+----------+------------------------------------------+--------------------+-----------+
207+
| id | username | password | email | is_active |
208+
+----+----------+------------------------------------------+--------------------+-----------+
209+
| 1 | admin | d033e22ae348aeb5660fc2140aec35850c4da997 | admin@example.com | 1 |
210+
+----+----------+------------------------------------------+--------------------+-----------+
235211
236212
The next part will focus on how to authenticate one of these users
237213
thanks to the Doctrine entity user provider and a couple of lines of
@@ -743,3 +719,46 @@ fetch the user and their associated roles with a single query::
743719
The ``QueryBuilder::leftJoin()`` method joins and fetches related roles from
744720
the ``AcmeUserBundle:User`` model class when a user is retrieved by their email
745721
address or username.
722+
723+
.. _`cookbook-security-serialize-equatable`:
724+
725+
Understanding serialize and how a User is Saved in the Session
726+
--------------------------------------------------------------
727+
728+
If you're curious about the importance of the ``serialize`` method inside
729+
the User class or how the User object is serialized or deserialized, then
730+
this section is for you. If not, feel free to skip this.
731+
732+
Once the user is logged in, the entire User object is serialized into the
733+
session. On the next request, the User object is deserialized. Then, value
734+
of the ``id`` property is used to re-query for a fresh User object from the
735+
database. Finally, the fresh User object is compared in some way to the deserialized
736+
User object to make sure that they represent the same user. For example, if
737+
the ``username`` on the 2 User objects doesn't match for some reason, then
738+
the user will be logged out for security reasons.
739+
740+
Even though this all happens automatically, there are a few important side-effects.
741+
742+
First, the :phpclass:`Serializable` interface and its ``serialize`` and ``unserialize``
743+
methods have been added to allow the ``User`` class to be serialized
744+
to the session. This may or may not be needed depending on your setup,
745+
but it's probably a good idea. Only the ``id`` needs to be serialized,
746+
because the :method:`Symfony\\Bridge\\Doctrine\\Security\\User\\EntityUserProvider::refreshUser`
747+
method refreshes the user on each request by using the ``id`` (as explained
748+
above). In practice, this means that the User object is reloaded from the
749+
database on each request using the ``id`` from the serialized object. This
750+
makes sure all of the User's data is fresh.
751+
752+
753+
Symfony also uses the ``username``, ``salt``, and ``password`` to verify
754+
that the User has not changed between requests. Failing to serialize
755+
these may cause you to be logged out on each request. If your User implements
756+
:class:`Symfony\\Component\\Security\\Core\\User\\EquatableInterface`,
757+
then instead of these properties being checked, your ``isEqualTo`` method
758+
is simply called, and you can check whatever properties you want. Unless
759+
you understand this, you probably *won't* need to implement this interface
760+
or worry about it.
761+
762+
.. versionadded:: 2.1
763+
In Symfony 2.1, the ``equals`` method was removed from ``UserInterface``
764+
and the ``EquatableInterface`` was added in its place.

0 commit comments

Comments
 (0)