Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Symfony Guard fire 'security.interactive_login' event on every request?

I have a Symfony 3.2 application which exposes a REST API and uses Json Web Tokens (JWT) for authentication. I recently switched to using Symfony's Guard component. Now my security.yml contains a firewall config section as follows (I'm using the Lexik JWT bundle 2.4.0, but this shouldn't matter):

firewalls:
    # ...
    api:
        pattern:   ^/api
        stateless: true
        guard:
            authenticators:
               - lexik_jwt_authentication.jwt_token_authenticator

Since I did this switch, I notice that every request is handled as if the user just logged in, i.e. a security.interactive_login event is fired. In the docs (http://symfony.com/doc/current/components/security/authentication.html#authentication-events) it states:

The security.interactive_login event is triggered after a user has actively logged into your website. It is important to distinguish this action from non-interactive authentication methods, such as: authentication based on a "remember me" cookie, authentication based on your session, authentication using a HTTP basic or HTTP digest header. You could listen on the security.interactive_login event, for example, in order to give your user a welcome flash message every time they log in.

So I definitely don't expect this event for every request - I'd rather expect to get the security.authentication.success event on every request, as pointed out in the docs.

However, Symfony's GuardAuthenticatorHandler class dispatches the security.interactive_login event in its authenticateWithToken method, and this method is called by the GuardAuthenticationListener on every request. Is that a bug in Symfony, a misunderstanding on my side, or due to incorrect configuration?

(This is not a philosophical question - in my case it leads to the concrete problem that the last login time of the user is updated on every request, which does not make sense.)

like image 391
dwytrykus Avatar asked May 24 '17 15:05

dwytrykus


1 Answers

I've come across your issue, because I've exactly the same problem. My workaround is to add a attribute in the request object, right before return true in the supports method of the guard.

Example:

public function supports(Request $request)
{
    ...

    $request->attributes->set('is_interactive_login', true);

    return true;
}

With this information you can check if it was a interactive login in the event listener

Example:

public function onLoginSuccess(InteractiveLoginEvent $event)
{
    $request = $event->getRequest();
    if ($request->attributes->get('is_interactive_login', false)) {
        // do whatever you need todo on interactive login
    }
}
like image 160
ddegasperi Avatar answered Oct 15 '22 04:10

ddegasperi