@@ -20,7 +20,7 @@ allows you to implement such a scheme really easily.
20
20
21
21
Your exact situation may differ, but in this example, a token is read
22
22
from an ``apikey `` query parameter, the proper username is loaded from that
23
- value, and then a User object is created::
23
+ value and then a User object is created::
24
24
25
25
// src/Acme/HelloBundle/Security/ApiKeyAuthenticator.php
26
26
namespace Acme\HelloBundle\Security;
@@ -59,7 +59,9 @@ value, and then a User object is created::
59
59
public function authenticateToken(TokenInterface $token, UserProviderInterface $userProvider, $providerKey)
60
60
{
61
61
$apiKey = $token->getCredentials();
62
- if (!$username = $this->userProvider->getUsernameForApiKey($apiKey)) {
62
+ $username = $this->userProvider->getUsernameForApiKey($apiKey)
63
+
64
+ if (!$username) {
63
65
throw new AuthenticationException(
64
66
sprintf('API Key "%s" does not exist.', $apiKey)
65
67
);
@@ -91,10 +93,10 @@ probably differ:
91
93
1. createToken
92
94
~~~~~~~~~~~~~~
93
95
94
- Early in the request cycle, Symfony calls ``createToken ``. Your job here
96
+ Early in the request cycle, Symfony calls ``createToken() ``. Your job here
95
97
is to create a token object that contains all of the information from the
96
98
request that you need to authenticate the user (e.g. the ``apikey `` query
97
- parameter). If that information is missing, throwing the
99
+ parameter). If that information is missing, throwing a
98
100
:class: `Symfony\\ Component\\ Security\\ Core\\ Exception\\ BadCredentialsException `
99
101
will cause authentication to fail.
100
102
@@ -106,11 +108,11 @@ will cause authentication to fail.
106
108
3. authenticateToken
107
109
~~~~~~~~~~~~~~~~~~~~
108
110
109
- If ``supportsToken `` returns ``true ``, Symfony will now call ``authenticateToken ``.
111
+ If ``supportsToken() `` returns ``true ``, Symfony will now call ``authenticateToken() ``.
110
112
One key part is the ``$userProvider ``, which is an external class that helps
111
113
you load information about the user. You'll learn more about this next.
112
114
113
- In this specific example, the following things happen in ``authenticateToken ``:
115
+ In this specific example, the following things happen in ``authenticateToken() ``:
114
116
115
117
#. First, you use the ``$userProvider `` to somehow look up the ``$username `` that
116
118
corresponds to the ``$apiKey ``;
@@ -119,18 +121,18 @@ In this specific example, the following things happen in ``authenticateToken``:
119
121
#. Finally, you create an *authenticated token * (i.e. a token with at least one
120
122
role) that has the proper roles and the User object attached to it.
121
123
122
- The goal is ultimately to use the ``$apiKey `` to find or create a User object.
123
- *How * you do this (e.g. query a database) and the exact class for your User
124
- object may vary. Those differences will be most obvious in your user provider.
124
+ The goal is ultimately to use the ``$apiKey `` to find or create a ``User ``
125
+ object. *How * you do this (e.g. query a database) and the exact class for
126
+ your ``User `` object may vary. Those differences will be most obvious in your
127
+ user provider.
125
128
126
129
The User Provider
127
130
~~~~~~~~~~~~~~~~~
128
131
129
- The ``$userProvider `` can be any user provider (see
130
- :doc: `how to create a custom user provider </cookbook/security/custom_provider >`).
132
+ The ``$userProvider `` can be any user provider (see :doc: `/cookbook/security/custom_provider `).
131
133
In this example, the ``$apiKey `` is used to somehow find the username for
132
- the user. This work is done in a ``getUsernameForApiKey `` method, which is
133
- created entirely custom for our use-case (i.e. this isn't a method that's
134
+ the user. This work is done in a ``getUsernameForApiKey() `` method, which
135
+ is created entirely custom for this use-case (i.e. this isn't a method that's
134
136
used by Symfony's core user provider system).
135
137
136
138
The ``$userProvider `` might look something like this::
@@ -140,14 +142,16 @@ The ``$userProvider`` might look something like this::
140
142
141
143
use Symfony\Component\Security\Core\User\UserProviderInterface;
142
144
use Symfony\Component\Security\Core\User\User;
145
+ use Symfony\Component\Security\Core\User\UserInterface;
146
+ use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
143
147
144
148
class ApiKeyUserProvider extends UserProviderInterface
145
149
{
146
150
public function getUsernameForApiKey($apiKey)
147
151
{
148
152
// Look up the username based on the token in the database, via
149
153
// an API call, or do something entirely different
150
- $username = // ...
154
+ $username = ...;
151
155
152
156
return $username;
153
157
}
@@ -174,7 +178,7 @@ The ``$userProvider`` might look something like this::
174
178
175
179
public function supportsClass($class)
176
180
{
177
- return $class === 'Symfony\Component\Security\Core\User\User';
181
+ return 'Symfony\Component\Security\Core\User\User' === $class ;
178
182
}
179
183
}
180
184
@@ -183,23 +187,23 @@ The ``$userProvider`` might look something like this::
183
187
Read the dedicated article to learn
184
188
:doc: `how to create a custom user provider </cookbook/security/custom_provider >`.
185
189
186
- The logic inside ``getUsernameForApiKey `` is up to you. You may somehow transform
190
+ The logic inside ``getUsernameForApiKey() `` is up to you. You may somehow transform
187
191
the API key (e.g. ``37b51d ``) into a username (e.g. ``jondoe ``) by looking
188
192
up some information in a "token" database table.
189
193
190
- The same is true for ``loadUserByUsername ``. In this example, Symfony's core
194
+ The same is true for ``loadUserByUsername() ``. In this example, Symfony's core
191
195
:class: `Symfony\\ Component\\ Security\\ Core\\ User\\ User ` class is simply created.
192
196
This makes sense if you don't need to store any extra information on your
193
197
User object (e.g. ``firstName ``). But if you do, you may instead have your *own *
194
198
user class which you create and populate here by querying a database. This
195
- would allow you to have custom data on the User object.
199
+ would allow you to have custom data on the `` User `` object.
196
200
197
- Finally, just make sure that ``supportsClass `` return ``true `` for User
198
- objects with the same class as whatever user you return in ``loadUserByUsername ``.
201
+ Finally, just make sure that ``supportsClass() `` returns ``true `` for User
202
+ objects with the same class as whatever user you return in ``loadUserByUsername() ``.
199
203
If your authentication is stateless like in this example (i.e. you expect
200
204
the user to send the API key with every request and so you don't save the
201
205
login to the session), then you can simply throw the ``UnsupportedUserException ``
202
- exception in ``refreshUser ``.
206
+ exception in ``refreshUser() ``.
203
207
204
208
.. note ::
205
209
@@ -212,9 +216,10 @@ Configuration
212
216
-------------
213
217
214
218
Once you have your ``ApiKeyAuthentication `` all setup, you need to register
215
- it as a service and use it in ``security.yml ``. First, register it as a service.
216
- This assumes that you have already setup your custom user provider as a service
217
- called ``your_api_key_user_provider `` (see :doc: `/cookbook/security/custom_provider `).
219
+ it as a service and use it in your security configuration (e.g. ``security.yml ``).
220
+ First, register it as a service. This assumes that you have already setup
221
+ your custom user provider as a service called ``your_api_key_user_provider ``
222
+ (see :doc: `/cookbook/security/custom_provider `).
218
223
219
224
.. configuration-block ::
220
225
@@ -260,8 +265,8 @@ called ``your_api_key_user_provider`` (see :doc:`/cookbook/security/custom_provi
260
265
array(new Reference('your_api_key_user_provider'))
261
266
));
262
267
263
- Now, activate it in the ``firewalls `` section of `` security.yml `` using the
264
- ``simple_preauth `` key:
268
+ Now, activate it in the ``firewalls `` section of your security configuration
269
+ using the ``simple_preauth `` key:
265
270
266
271
.. configuration-block ::
267
272
@@ -395,32 +400,31 @@ configuration or set it to ``false``:
395
400
Storing authentication information in the session works like this:
396
401
397
402
#. At the end of each request, Symfony serializes the token object (returned
398
- from ``authenticateToken ``), which also serializes the User object (since
399
- it's set on a property on the token);
400
- #. On the next request the token is deserialized and the deserialized User
401
- object is passed to the ``refreshUser `` function of the user provider.
403
+ from ``authenticateToken() ``), which also serializes the `` User `` object
404
+ (since it's set on a property on the token);
405
+ #. On the next request the token is deserialized and the deserialized `` User ``
406
+ object is passed to the ``refreshUser() `` function of the user provider.
402
407
403
- The second step is the important one: Symfony calls ``refreshUser `` and passes
408
+ The second step is the important one: Symfony calls ``refreshUser() `` and passes
404
409
you the user object that was serialized in the session. If your users are
405
410
stored in the database, then you may want to re-query for a fresh version
406
411
of the user to make sure it's not out-of-date. But regardless of your requirements,
407
- ``refreshUser `` should now return the User object::
412
+ ``refreshUser() `` should now return the User object::
408
413
409
414
// src/Acme/HelloBundle/Security/ApiKeyUserProvider.php
410
415
411
416
// ...
412
-
413
417
class ApiKeyUserProvider extends UserProviderInterface
414
418
{
415
419
// ...
416
420
417
421
public function refreshUser(UserInterface $user)
418
422
{
419
- // $user is the User that you set in the token inside authenticateToken
423
+ // $user is the User that you set in the token inside authenticateToken()
420
424
// after it has been deserialized from the session
421
425
422
426
// you might use $user to query the database for a fresh user
423
- $id = $user->getId();
427
+ // $id = $user->getId();
424
428
// use $id to make a query
425
429
426
430
// if you are *not* reading from a database and are just creating
@@ -431,12 +435,12 @@ of the user to make sure it's not out-of-date. But regardless of your requiremen
431
435
432
436
.. note ::
433
437
434
- You'll also want to make sure that your User object is being serialized
435
- correctly. If your User object has private properties, PHP can't serialize
438
+ You'll also want to make sure that your `` User `` object is being serialized
439
+ correctly. If your `` User `` object has private properties, PHP can't serialize
436
440
those. In this case, you may get back a User object that has a ``null ``
437
441
value for each property. For an example, see :doc: `/cookbook/security/entity_provider `.
438
442
439
- Only Authenticating for certain URLs
443
+ Only Authenticating for Certain URLs
440
444
------------------------------------
441
445
442
446
This entry has assumed that you want to look for the ``apikey `` authentication
@@ -445,12 +449,13 @@ really need to look for authentication information once the user has reached
445
449
a certain URL (e.g. the redirect URL in OAuth).
446
450
447
451
Fortunately, handling this situation is easy: just check to see what the
448
- current URL is before creating the token in ``createToken ``::
452
+ current URL is before creating the token in ``createToken() ``::
449
453
450
454
// src/Acme/HelloBundle/Security/ApiKeyAuthenticator.php
451
455
452
456
// ...
453
457
use Symfony\Component\Security\Http\HttpUtils;
458
+ use Symfony\Component\HttpFoundation\Request;
454
459
455
460
class ApiKeyAuthenticator implements SimplePreAuthenticatorInterface
456
461
{
@@ -477,8 +482,8 @@ current URL is before creating the token in ``createToken``::
477
482
}
478
483
}
479
484
480
- This uses a handy :class: `Symfony\\ Component\\ Security\\ Http\\ HttpUtils `
481
- class to see if the current URL matches the URL you're looking for. In this
485
+ This uses the handy :class: `Symfony\\ Component\\ Security\\ Http\\ HttpUtils `
486
+ class to check if the current URL matches the URL you're looking for. In this
482
487
case, the URL (``/login/check ``) has been hardcoded in the class, but you
483
488
could also inject it as the third constructor argument.
484
489
0 commit comments