8000 Avoiding authentication on every request with Guard · symfony/symfony-docs@d2f062a · GitHub
[go: up one dir, main page]

Skip to content

Commit d2f062a

Browse files
committed
Avoiding authentication on every request with Guard
1 parent 35098ee commit d2f062a

File tree

1 file changed

+97
-0
lines changed

1 file changed

+97
-0
lines changed

security/guard_authentication.rst

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,103 @@ egg to return a custom message if someone tries this:
491491
curl -H "X-AUTH-TOKEN: ILuvAPIs" http://localhost:8000/
492492
# {"message":"ILuvAPIs is not a real API key: it's just a silly phrase"}
493493
494+
Avoid Authenticating the Browser on Every Request
495+
-------------------------------------------------
496+
497+
If you create a Guard login system that's used by a browser and you're experiencing
498+
problems with your session or CSRF tokens, the cause could be bad behavior by your
499+
authenticator. When a Guard authenticator is meant to be used by a browser, you
500+
should *not* authenticate the user on *every* request. In other words, you need to
501+
make sure the ``getCredentials()`` method *only* returns a non-null value when
502+
you actually *need* to authenticate the user. Why? Because, when ``getCredentials()``
503+
returns a non-null value, for security purposes, the user's session is "migrated"
504+
to a new session id.
505+
506+
This is an edge-case, and unless you're having session or CSRF token issues, you
507+
can ignore this. Here is an example of good and bad behavior::
508+
509+
public function getCredentials(Request $request)
510+
{
511+
// GOOD behavior: only authenticate on a specific route
512+
if ($request->attributes->get('_route') !== 'login_route' || !$request->isMethod('POST')) {
513+
return null;
514+
}
515+
516+
// e.g. your login system authenticates by the user's IP address
517+
// BAD behavior: authentication will now execute on every request
518+
// even if the user is already authenticated (due to the session)
519+
return array('ip' => $request->getClientIp());
520+
}
521+
522+
The problem occurs when your browser-based authenticator tries to authenticate
523+
the user on *every* request - like in the IP address-based example above. There
524+
are two possible fixes:
525+
526+
1) If you do *not* need authentication to be stored in the session, set ``stateless: true``
527+
under your firewall.
528+
529+
2) Update your authenticator to avoid authentication if the user is already authenticated:
530+
531+
.. code-block:: diff
532+
533+
// src/Security/MyIpAuthenticator.php
534+
// ...
535+
536+
+ use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
537+
538+
class MyIpAuthenticator
539+
{
540+
+ private $tokenStorage;
541+
542+
+ public function __construct(TokenStorageInterface $tokenStorage)
543+
+ {
544+
+ $this->tokenStorage = $tokenStorage;
545+
+ }
546+
547+
public function getCredentials(Request $request)
548+
{
549+
+ // if there is already an authenticated user (likely due to the session)
550+
+ // then return null and skip authentication: there is no need.
551+
+ $user = $this->tokenStorage->getToken() ? $this->tokenStorage->getToken()->getUser() : null;
552+
+ if (is_object($user)) {
553+
+ return null;
554+
+ }
555+
556+
return array('ip' => $request->getClientIp());
557+
}
558+
}
559+
560+
You'll also need to update your service configuration to pass the token storage:
561+
562+
.. configuration-block::
563+
564+
.. code-block:: yaml
565+
566+
# app/config/services.yml
567+
services:
568+
app.token_authenticator:
569+
class: AppBundle\Security\TokenAuthenticator
570+
arguments: ['@security.token_storage']
571+
572+
.. code-block:: xml
573+
574+
<!-- app/config/services.xml -->
575+
<services>
576+
<service id="app.token_authenticator" class="AppBundle\Security\TokenAuthenticator">
577+
<argument type="service" id="security.token_storage" />
578+
</service>
579+
</services>
580+
581+
.. code-block:: php
582+
583+
// app/config/services.php
584+
use AppBundle\Security\TokenAuthenticator;
585+
use Symfony\Component\DependencyInjection\Definition;
586+
use Symfony\Component\DependencyInjection\Reference;
587+
588+
$container->register('app.token_authenticator', TokenAuthenticator::class)
589+
->addArgument(new Reference('security.token_storage'));
590+
494591
Frequently Asked Questions
495592
--------------------------
496593

0 commit comments

Comments
 (0)
0