@@ -28,6 +28,9 @@ creates a ``security.yaml`` configuration file for you:
28
28
security :
29
29
# https://symfony.com/doc/current/security/experimental_authenticators.html
30
30
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'
31
34
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
32
35
providers :
33
36
users_in_memory : { memory: null }
@@ -79,7 +82,7 @@ The User
79
82
Permissions in Symfony are always linked to a user object. If you need to
80
83
secure (parts of) your application, you need to create a user class. This
81
84
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
83
86
Security user class.
84
87
85
88
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:
324
327
**Reload the User from the session **
325
328
At the beginning of each request, the user is loaded from the
326
329
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
329
332
necessary, the user is de-authenticated/logged out if something
330
333
changed). See :ref: `user_session_refresh ` for more information about
331
334
this process.
@@ -341,7 +344,7 @@ Symfony comes with several built-in user providers:
341
344
:ref: `Chain User Provider <security-chain-user-provider >`
342
345
Merges two or more user providers into a new user provider.
343
346
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
345
348
can also create your own :ref: `custom user provider <security-custom-user-provider >`.
346
349
347
350
.. note ::
@@ -350,14 +353,16 @@ can also create your own :ref:`custom user provider <security-custom-user-provid
350
353
in your custom authenticator). All user providers follow this pattern
351
354
for their service ID: ``security.user.provider.concrete.<your-provider-name> ``
352
355
(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\C omponent\S ecurity\C ore\U ser\U serProviderInterface `
358
+ type-hint.
354
359
355
360
.. _security-encoding-user-password :
356
361
357
362
Registering the User: Hashing Passwords
358
363
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
359
364
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
361
366
applications, the SecurityBundle provides password hashing and verification
362
367
functionality.
363
368
@@ -382,8 +387,9 @@ First, make sure your User class implements the
382
387
}
383
388
}
384
389
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:
387
393
388
394
.. configuration-block ::
389
395
@@ -393,10 +399,9 @@ Then, configure which password hasher should be used for this class. The
393
399
security :
394
400
# ...
395
401
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'
400
405
401
406
.. code-block :: xml
402
407
@@ -414,22 +419,22 @@ Then, configure which password hasher should be used for this class. The
414
419
<!-- ... -->
415
420
<!-- Use native password hasher, which auto-selects and migrates the best
416
421
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" />
418
423
</config >
419
424
</srv : container >
420
425
421
426
.. code-block :: php
422
427
423
428
// config/packages/security.php
424
429
use App\Entity\User;
425
- use Symfony\Config\SecurityConfig ;
430
+ use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface ;
426
431
427
432
return static function (SecurityConfig $security) {
428
433
// ...
429
434
430
435
// Use native password hasher, which auto-selects and migrates the best
431
436
// possible hashing algorithm (starting from Symfony 5.3 this is "bcrypt")
432
- $security->passwordHasher(User ::class)
437
+ $security->passwordHasher(PasswordAuthenticatedUserInterface ::class)
433
438
->algorithm('auto')
434
439
;
435
440
};
@@ -591,7 +596,7 @@ you'll see that you're visiting a page behind the firewall in the toolbar:
591
596
.. image :: /_images/security/anonymous_wdt.png
592
597
:align: center
593
598
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
595
600
(e.g. the login form has to be accessible or some parts of your application
596
601
are public). You'll learn how to restrict access to URLs, controllers or
597
602
anything else within your firewall in the :ref: `access control
@@ -769,13 +774,13 @@ Edit the login controller to render the login form:
769
774
}
770
775
}
771
776
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.
777
782
778
- Finally, create the template:
783
+ Finally, create or updaate the template:
779
784
780
785
.. code-block :: html+twig
781
786
@@ -790,7 +795,7 @@ Finally, create the template:
790
795
{% endif %}
791
796
792
797
<form action="{{ path('login') }}" method="post">
793
- <label for="username">Username :</label>
798
+ <label for="username">Email :</label>
794
799
<input type="text" id="username" name="_username" value="{{ last_username }}"/>
795
800
796
801
<label for="password">Password:</label>
@@ -808,15 +813,16 @@ Finally, create the template:
808
813
The ``error `` variable passed into the template is an instance of
809
814
:class: `Symfony\\ Component\\ Security\\ Core\\ Exception\\ AuthenticationException `.
810
815
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,
812
817
as shown in the example. This message is always safe to display.
813
818
814
819
The form can look like anything, but it usually follows some conventions:
815
820
816
821
* 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 ``.
820
826
821
827
.. tip ::
822
828
@@ -829,20 +835,21 @@ The form can look like anything, but it usually follows some conventions:
829
835
:ref: `form_login-csrf ` on how to protect your login form.
830
836
831
837
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.
834
841
835
842
To review the whole process:
836
843
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 ``) ;
838
845
#. The firewall initiates the authentication process by redirecting the
839
846
user to the login form (``/login ``);
840
847
#. The ``/login `` page renders login form via the route and controller created
841
848
in this example;
842
849
#. 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.
846
853
847
854
.. _form_login-csrf :
848
855
@@ -940,8 +947,8 @@ JSON Login
940
947
941
948
Some applications provide an API that is secured using tokens. These
942
949
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.
945
952
946
953
Enable the authenticator using the ``json_login `` setting:
947
954
@@ -957,6 +964,7 @@ Enable the authenticator using the ``json_login`` setting:
957
964
main :
958
965
# ...
959
966
json_login :
967
+ # app_login is a route we will create below
960
968
check_path : api_login
961
969
962
970
.. code-block :: xml
@@ -1045,7 +1053,7 @@ token (or whatever you need to return) and return the JSON response:
1045
1053
- public function index(): Response
1046
1054
+ public function index(#[CurrentUser] User $user): Response
1047
1055
{
1048
- + $token = ...; // somehow create a token for $user
1056
+ + $token = ...; // somehow create an API token for $user
1049
1057
+
1050
1058
return $this->json([
1051
1059
- 'message' => 'Welcome to your new controller!',
@@ -1065,12 +1073,14 @@ token (or whatever you need to return) and return the JSON response:
1065
1073
That's it! To summarize the process:
1066
1074
1067
1075
#. 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:
1069
1079
1070
1080
.. code-block :: json
1071
1081
1072
1082
{
1073
- "username" : " dunglas" ,
1083
+ "username" : " dunglas@example.com " ,
1074
1084
"password" : " MyPassword"
1075
1085
}
1076
1086
#. The security system intercepts the request, checks the user's submitted
@@ -1082,7 +1092,7 @@ That's it! To summarize the process:
1082
1092
.. code-block :: json
1083
1093
1084
1094
{
1085
- "user" : " dunglas" ,
1095
+ "user" : " dunglas@example.com " ,
1086
1096
"token" : " 45be42..."
1087
1097
}
1088
1098
@@ -2510,21 +2520,23 @@ However, in some cases, this process can cause unexpected authentication problem
2510
2520
If you're having problems authenticating, it could be that you *are * authenticating
2511
2521
successfully, but you immediately lose authentication after the first redirect.
2512
2522
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.
2515
2526
2516
2527
Comparing Users Manually with EquatableInterface
2517
2528
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2518
2529
2519
2530
Or, if you need more control over the "compare users" process, make your User class
2520
2531
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.
2522
2534
2523
2535
Security Events
2524
2536
---------------
2525
2537
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
2528
2540
can do this by creating an :doc: `event listener or subscriber </event_dispatcher >`
2529
2541
for these events.
2530
2542
@@ -2542,7 +2554,7 @@ Authentication Events
2542
2554
2543
2555
:class: `Symfony\\ Component\\ Security\\ Http\\ Event\\ AuthenticationTokenCreatedEvent `
2544
2556
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
2546
2558
where you need to modify the created token (e.g. for multi factor
2547
2559
authentication).
2548
2560
@@ -2553,12 +2565,12 @@ Authentication Events
2553
2565
2554
2566
:class: `Symfony\\ Component\\ Security\\ Http\\ Event\\ LoginSuccessEvent `
2555
2567
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.
2557
2569
2558
2570
:class: `Symfony\\ Component\\ Security\\ Http\\ Event\\ LoginFailureEvent `
2559
- Dispatched after an ``AuthenticationException `` was thrown during the
2571
+ Dispatched after an ``AuthenticationException `` was thrown during
2560
2572
authentication. Listeners to this event can modify the error response
2561
- send back to the user.
2573
+ sent back to the user.
2562
2574
2563
2575
Other Events
2564
2576
~~~~~~~~~~~~
0 commit comments