Skip to content

Commit df05fdb

Browse files
committed
Various tweaks to the new security documentation
1 parent d5460ed commit df05fdb

File tree

2 files changed

+66
-55
lines changed

2 files changed

+66
-55
lines changed

security.rst

Lines changed: 60 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ creates a ``security.yaml`` configuration file for you:
2828
security:
2929
# https://symfony.com/doc/current/security/experimental_authenticators.html
3030
enable_authenticator_manager: true
31+
# https://symfony.com/doc/current/security.html#c-hashing-passwords
32+
password_hashers:
33+
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
3134
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
3235
providers:
3336
users_in_memory: { memory: null }
@@ -79,7 +82,7 @@ The User
7982
Permissions in Symfony are always linked to a user object. If you need to
8083
secure (parts of) your application, you need to create a user class. This
8184
is a class that implements :class:`Symfony\\Component\\Security\\Core\\User\\UserInterface`.
82-
This class is often a Doctrine entity, but you can also use a dedicated
85+
This is often a Doctrine entity, but you can also use a dedicated
8386
Security user class.
8487

8588
The easiest way to generate a user class is using the ``make:user`` command
@@ -324,8 +327,8 @@ User providers are used in a couple places during the security lifecycle:
324327
**Reload the User from the session**
325328
At the beginning of each request, the user is loaded from the
326329
session (unless your firewall is ``stateless``). The provider
327-
"refreshes" the user (e.g. the database is queried again for fresh
328-
data), to make sure all user information is up to date (and if
330+
"refreshes" the user (e.g. the database is queried again for fresh
331+
data) to make sure all user information is up to date (and if
329332
necessary, the user is de-authenticated/logged out if something
330333
changed). See :ref:`user_session_refresh` for more information about
331334
this process.
@@ -341,7 +344,7 @@ Symfony comes with several built-in user providers:
341344
:ref:`Chain User Provider <security-chain-user-provider>`
342345
Merges two or more user providers into a new user provider.
343346

344-
The built-in user providers cover most the common needs for applications, but you
347+
The built-in user providers cover the most common needs for applications, but you
345348
can also create your own :ref:`custom user provider <security-custom-user-provider>`.
346349

347350
.. note::
@@ -350,14 +353,16 @@ can also create your own :ref:`custom user provider <security-custom-user-provid
350353
in your custom authenticator). All user providers follow this pattern
351354
for their service ID: ``security.user.provider.concrete.<your-provider-name>``
352355
(where ``<your-provider-name>`` is the configuration key, e.g.
353-
``app_user_provider``).
356+
``app_user_provider``). If you only have one user provider, you can autowire
357+
it using the :class:`Symfony\Component\Security\Core\User\UserProviderInterface`
358+
type-hint.
354359

355360
.. _security-encoding-user-password:
356361

357362
Registering the User: Hashing Passwords
358363
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
359364

360-
Most applications require a user to login with a password. For these
365+
Many applications require a user to log in with a password. For these
361366
applications, the SecurityBundle provides password hashing and verification
362367
functionality.
363368

@@ -382,8 +387,9 @@ First, make sure your User class implements the
382387
}
383388
}
384389

385-
Then, configure which password hasher should be used for this class. The
386-
``make:user`` pre-configured this for you:
390+
Then, configure which password hasher should be used for this class. If your
391+
``security.yaml`` file wasn't already pre-configured, then ``make:user`` should
392+
have done this for you:
387393

388394
.. configuration-block::
389395

@@ -393,10 +399,9 @@ Then, configure which password hasher should be used for this class. The
393399
security:
394400
# ...
395401
password_hashers:
396-
App\Entity\User:
397-
# Use native password hasher, which auto-selects and migrates the best
398-
# possible hashing algorithm (starting from Symfony 5.3 this is "bcrypt")
399-
algorithm: auto
402+
# Use native password hasher, which auto-selects and migrates the best
403+
# possible hashing algorithm (starting from Symfony 5.3 this is "bcrypt")
404+
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
400405
401406
.. code-block:: xml
402407
@@ -414,22 +419,22 @@ Then, configure which password hasher should be used for this class. The
414419
<!-- ... -->
415420
<!-- Use native password hasher, which auto-selects and migrates the best
416421
possible hashing algorithm (starting from Symfony 5.3 this is "bcrypt") -->
417-
<password-hasher class="App\Entity\User" algorithm="auto"/>
422+
<password-hasher class="Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface" algorithm="auto"/>
418423
</config>
419424
</srv:container>
420425
421426
.. code-block:: php
422427
423428
// config/packages/security.php
424429
use App\Entity\User;
425-
use Symfony\Config\SecurityConfig;
430+
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
426431
427432
return static function (SecurityConfig $security) {
428433
// ...
429434
430435
// Use native password hasher, which auto-selects and migrates the best
431436
// possible hashing algorithm (starting from Symfony 5.3 this is "bcrypt")
432-
$security->passwordHasher(User::class)
437+
$security->passwordHasher(PasswordAuthenticatedUserInterface::class)
433438
->algorithm('auto')
434439
;
435440
};
@@ -591,7 +596,7 @@ you'll see that you're visiting a page behind the firewall in the toolbar:
591596
.. image:: /_images/security/anonymous_wdt.png
592597
:align: center
593598

594-
Visiting a secured section doesn't necessarily require you to authenticate
599+
Visiting a URL under a firewall doesn't necessarily require you to be authenticated
595600
(e.g. the login form has to be accessible or some parts of your application
596601
are public). You'll learn how to restrict access to URLs, controllers or
597602
anything else within your firewall in the :ref:`access control
@@ -769,13 +774,13 @@ Edit the login controller to render the login form:
769774
}
770775
}
771776
772-
Don't let this controller confuse you. The form login authenticators
773-
handles the form submission for you. If the user submits an invalid
774-
username or password, this controller reads the form submission error from
775-
the security system (using ``AuthenticationUtils``), so that it can be
776-
displayed back to the user.
777+
Don't let this controller confuse you. Its job is only to *render* the form:
778+
the ``form_login`` authenticator will handle the form *submission* automatically.
779+
If the user submits an invalid email or password, that authenticator will store
780+
the error and redirect back to this controller, where we read the error (using
781+
``AuthenticationUtils``) so that it can be displayed back to the user.
777782

778-
Finally, create the template:
783+
Finally, create or updaate the template:
779784

780785
.. code-block:: html+twig
781786

@@ -790,7 +795,7 @@ Finally, create the template:
790795
{% endif %}
791796

792797
<form action="{{ path('login') }}" method="post">
793-
<label for="username">Username:</label>
798+
<label for="username">Email:</label>
794799
<input type="text" id="username" name="_username" value="{{ last_username }}"/>
795800

796801
<label for="password">Password:</label>
@@ -808,15 +813,16 @@ Finally, create the template:
808813
The ``error`` variable passed into the template is an instance of
809814
:class:`Symfony\\Component\\Security\\Core\\Exception\\AuthenticationException`.
810815
It may contain sensitive information about the authentication failure.
811-
*Never* use ``error.message``, but the ``messageKey`` property instead
816+
*Never* use ``error.message``: use the ``messageKey`` property instead,
812817
as shown in the example. This message is always safe to display.
813818

814819
The form can look like anything, but it usually follows some conventions:
815820

816821
* The ``<form>`` element sends a ``POST`` request to the ``login`` route, since
817-
that's what you configured under the ``form_login`` key in ``security.yaml``;
818-
* The username field has the name ``_username`` and the password field has the
819-
name ``_password``.
822+
that's what you configured as the ``check_path`` under the ``form_login`` key in
823+
``security.yaml``;
824+
* The username (or whatever your user's "identifier" is, like an email) field has
825+
the name ``_username`` and the password field has the name ``_password``.
820826

821827
.. tip::
822828

@@ -829,20 +835,21 @@ The form can look like anything, but it usually follows some conventions:
829835
:ref:`form_login-csrf` on how to protect your login form.
830836

831837
And that's it! When you submit the form, the security system automatically
832-
checks the user's credentials and either authenticate the user or send the
833-
user back to the login form where the error can be displayed.
838+
reads the ``_username`` and ``_email`` POST parameter, loads the user via
839+
the user provider, checks the user's credentials and either authenticates the
840+
user or sends them back to the login form where the error can be displayed.
834841

835842
To review the whole process:
836843

837-
#. The user tries to access a resource that is protected;
844+
#. The user tries to access a resource that is protected (e.g. ``/admin``);
838845
#. The firewall initiates the authentication process by redirecting the
839846
user to the login form (``/login``);
840847
#. The ``/login`` page renders login form via the route and controller created
841848
in this example;
842849
#. The user submits the login form to ``/login``;
843-
#. The security system intercepts the request, checks the user's submitted
844-
credentials, authenticates the user if they are correct, and sends the
845-
user back to the login form if they are not.
850+
#. The security system (i.e. the ``form_login`` authenticator) intercepts the
851+
request, checks the user's submitted credentials, authenticates the user if
852+
they are correct, and sends the user back to the login form if they are not.
846853

847854
.. _form_login-csrf:
848855

@@ -940,8 +947,8 @@ JSON Login
940947

941948
Some applications provide an API that is secured using tokens. These
942949
applications may use an endpoint that provides these tokens based on a
943-
username and password. The JSON login authenticator helps you create this
944-
functionality.
950+
username (or email) and password. The JSON login authenticator helps you create
951+
this functionality.
945952

946953
Enable the authenticator using the ``json_login`` setting:
947954

@@ -957,6 +964,7 @@ Enable the authenticator using the ``json_login`` setting:
957964
main:
958965
# ...
959966
json_login:
967+
# app_login is a route we will create below
960968
check_path: api_login
961969
962970
.. code-block:: xml
@@ -1045,7 +1053,7 @@ token (or whatever you need to return) and return the JSON response:
10451053
- public function index(): Response
10461054
+ public function index(#[CurrentUser] User $user): Response
10471055
{
1048-
+ $token = ...; // somehow create a token for $user
1056+
+ $token = ...; // somehow create an API token for $user
10491057
+
10501058
return $this->json([
10511059
- 'message' => 'Welcome to your new controller!',
@@ -1065,12 +1073,14 @@ token (or whatever you need to return) and return the JSON response:
10651073
That's it! To summarize the process:
10661074

10671075
#. A client (e.g. the front-end) makes a *POST request* with the
1068-
``Content-Type: application/json`` header to ``/api/login``:
1076+
``Content-Type: application/json`` header to ``/api/login`` with
1077+
``username`` (even if your identifier is actually an email) and
1078+
``password`` keys:
10691079

10701080
.. code-block:: json
10711081
10721082
{
1073-
"username": "dunglas",
1083+
"username": "dunglas@example.com",
10741084
"password": "MyPassword"
10751085
}
10761086
#. The security system intercepts the request, checks the user's submitted
@@ -1082,7 +1092,7 @@ That's it! To summarize the process:
10821092
.. code-block:: json
10831093
10841094
{
1085-
"user": "dunglas",
1095+
"user": "dunglas@example.com",
10861096
"token": "45be42..."
10871097
}
10881098
@@ -2510,21 +2520,23 @@ However, in some cases, this process can cause unexpected authentication problem
25102520
If you're having problems authenticating, it could be that you *are* authenticating
25112521
successfully, but you immediately lose authentication after the first redirect.
25122522

2513-
In that case, review the serialization logic (e.g. ``SerializableInterface``) if
2514-
you have any, to make sure that all the fields necessary are serialized.
2523+
In that case, review the serialization logic (e.g. ``SerializableInterface``) on
2524+
you user class (if you have any) to make sure that all the fields necessary are
2525+
serialized.
25152526

25162527
Comparing Users Manually with EquatableInterface
25172528
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
25182529

25192530
Or, if you need more control over the "compare users" process, make your User class
25202531
implement :class:`Symfony\\Component\\Security\\Core\\User\\EquatableInterface`.
2521-
Then, your ``isEqualTo()`` method will be called when comparing users.
2532+
Then, your ``isEqualTo()`` method will be called when comparing users instead
2533+
of the core logic.
25222534

25232535
Security Events
25242536
---------------
25252537

2526-
During the authentication process, multiple events are dispatched to
2527-
hook into the process or customize the response sent back to the user. You
2538+
During the authentication process, multiple events are dispatched that allow you
2539+
to hook into the process or customize the response sent back to the user. You
25282540
can do this by creating an :doc:`event listener or subscriber </event_dispatcher>`
25292541
for these events.
25302542

@@ -2542,7 +2554,7 @@ Authentication Events
25422554

25432555
:class:`Symfony\\Component\\Security\\Http\\Event\\AuthenticationTokenCreatedEvent`
25442556
Dispatched after the passport was validated and the authenticator
2545-
created the security token. This can be used in advanced use-cases
2557+
created the security token (and user). This can be used in advanced use-cases
25462558
where you need to modify the created token (e.g. for multi factor
25472559
authentication).
25482560

@@ -2553,12 +2565,12 @@ Authentication Events
25532565

25542566
:class:`Symfony\\Component\\Security\\Http\\Event\\LoginSuccessEvent`
25552567
Dispatched after authentication was fully successful. Listeners to this
2556-
event can modify the response send back to the user.
2568+
event can modify the response sent back to the user.
25572569

25582570
:class:`Symfony\\Component\\Security\\Http\\Event\\LoginFailureEvent`
2559-
Dispatched after an ``AuthenticationException`` was thrown during the
2571+
Dispatched after an ``AuthenticationException`` was thrown during
25602572
authentication. Listeners to this event can modify the error response
2561-
send back to the user.
2573+
sent back to the user.
25622574

25632575
Other Events
25642576
~~~~~~~~~~~~

security/custom_authenticator.rst

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
How to Write a Custom Authenticator
22
===================================
33

4-
Symfony comes with :ref:`many autenticators <security-authenticators>` and
4+
Symfony comes with :ref:`many authenticators <security-authenticators>` and
55
third party bundles also implement more complex cases like JWT and oAuth
66
2.0. However, sometimes you need to implement a custom authentication
77
mechanism that doesn't exists yet or you need to customize one. In such
@@ -146,9 +146,9 @@ into a security
146146

147147
.. tip::
148148

149-
If you want to customize the login form, you can also extend from the
149+
If your custom authenticator is a login form, you can extend from the
150150
:class:`Symfony\\Component\\Security\\Http\\Authenticator\\AbstractLoginFormAuthenticator`
151-
class instead.
151+
class instead to make your job easier.
152152

153153
.. _security-passport:
154154

@@ -166,7 +166,7 @@ or if "remember me" functionality should be enabled.
166166

167167
The default
168168
:class:`Symfony\\Component\\Security\\Http\\Authenticator\\Passport\\Passport`
169-
requires a user and credentials.
169+
requires a user and some sort of "credentials" (e.g. a password).
170170

171171
Use the
172172
:class:`Symfony\\Component\\Security\\Http\\Authenticator\\Passport\\Badge\\UserBadge`
@@ -250,8 +250,7 @@ Self Validating Passport
250250
If you don't need any credentials to be checked (e.g. when using API
251251
tokens), you can use the
252252
:class:`Symfony\\Component\\Security\\Http\\Authenticator\\Passport\\SelfValidatingPassport`.
253-
This class only requires a ``UserBadge`` object and optionally `Passport
254-
Badges`_.
253+
This class only requires a ``UserBadge`` object and optionally `Passport Badges`_.
255254

256255
Passport Badges
257256
---------------
@@ -268,7 +267,7 @@ the following badges are supported:
268267

269268
:class:`Symfony\\Component\\Security\\Http\\Authenticator\\Passport\\Badge\\PasswordUpgradeBadge`
270269
This is used to automatically upgrade the password to a new hash upon
271-
successful login. This badge requires the plaintext password and a
270+
successful login (if needed). This badge requires the plaintext password and a
272271
password upgrader (e.g. the user repository). See :ref:`security-password-migration`.
273272

274273
:class:`Symfony\\Component\\Security\\Http\\Authenticator\\Passport\\Badge\\CsrfTokenBadge`

0 commit comments

Comments
 (0)