6

I would like to have some action after a success authentification.

I created a class extended DefaultAuthenticationSuccessHandler, and redefined the onAuthenticationSuccess function.

Though the authentication is a success, the programm never goes to the function : why ?


namespace my_name_space;

use   Symfony\Component\Security\Http\Authentication\DefaultAuthenticationSuccessHandler;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Security\Http\HttpUtils;
use Symfony\Bridge\Monolog\Logger;


class AuthenticationSuccessHandler extends DefaultAuthenticationSuccessHandler {
private $em;
private $logger;

function __construct(Logger $logger, HttpUtils $httpUtils, EntityManager $em) {
    parent::__construct($httpUtils);
    $this->em = $em;
    $this->logger = $logger;
}

public function onAuthenticationSuccess(Request $request, TokenInterface $token) {
    $this->logger->info("onAuthenticationSuccess");
    $response = parent::onAuthenticationSuccess($request, $token);
    $token->eraseCredentials();        
    $token->getUser()->addRole('ROLE_USER');

    return $response;
}

}

services:
security.authentication.success.handler:
    class: MY\NAMESPACE\AuthenticationSuccessHandler
    arguments: ["@monolog.logger.php","@security.http_utils", "@doctrine.orm.default_entity_manager"]

security.yml

form_login:
            check_path: _security_check
            use_referer: true
            use_forward: true
            login_path: my_login
            success_handler: security.authentication.success.handler
mlwacosmos
  • 4,391
  • 16
  • 66
  • 114
  • 1
    Are you [define success hundler in the firewall](http://stackoverflow.com/questions/15908856/do-something-just-after-symfony2-login-success-and-before-redirect)? Maybe you can provide more detais about security configeration? – Dmytro Feb 26 '16 at 13:07
  • that must be that... right (though the constructor is called).. how do I do that ? I just added in the form_login of the security.yml the success_handler: security.authentication.success.handler option – mlwacosmos Feb 26 '16 at 13:08
  • 1
    You should set here `success_handler: security.authentication.success.handler` your service name – Dmytro Feb 26 '16 at 13:12
  • Please add your service declaration + the firewall from security.yml – chalasr Feb 26 '16 at 13:30
  • 've found any good answer ? i'm not ok with the answer . It does not say why it does not work. – julio Mar 07 '17 at 10:57

3 Answers3

5

You can listen for the event that is triggered after a successful login attempt by registering a service to the related security tag:

app.login_listener:
    class: AppBundle\EventListener\LoginListener
    arguments:
        - @security.authorization_checker
        - @security.token_storage
    tags:
        - { name: kernel.event_listener, event: security.interactive_login, method: yourMethod }

Where yourMethod can contain the code you want to execute.

Rvanlaak
  • 2,971
  • 20
  • 40
  • really... why can't i Use the default on success handler which should call the onAuthenticationSuccess method that I redefined ? – mlwacosmos Feb 26 '16 at 13:35
  • Think the success_listener notation is wrong, instead of `security.authentication.success.handler` you should call the service `"@security.authentication.success.handler"`. – Rvanlaak Feb 26 '16 at 13:39
  • you mean in the security.yml ? I say it again (the constructor of this class is called) – mlwacosmos Feb 26 '16 at 13:41
  • Think you are somehow trying to override / decorate the default service because the service keys are identical, see http://stackoverflow.com/questions/15918617/symfony2-extending-defaultauthenticationsuccesshandler and http://stackoverflow.com/questions/27826964/success-handler-not-working-after-symfony2-login – Rvanlaak Feb 26 '16 at 13:52
  • I know this post and it is like mine.. but the method is not triggered – mlwacosmos Feb 26 '16 at 13:57
3

There are a lot of same issues on SO, github, google groups, most of them are unsolved.

Also, you should define a custom AuthenticationSuccessHandler rather than extending the default.

Example:

services.yml

login_success_handler:
    class:  YourBundle\EventListener\CustomAuthenticationSuccessHandler
    arguments:  ["@doctrine", "@router"]
    tags:
        - { name: kernel.event_listener, event: security.interactive_login, method: onSecurityInteractiveLogin }

CustomAuthenticationSuccessHandler.php

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\HttpFoundation\Routing\RouterInterface;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
use Doctrine\ORM\EntityManager;

class CustomAuthenticationSuccessHandler {
    private $em;
    private $logger;

    public function __construct(EntityManager $em, RouterInterface $router) 
    {
        $this->em = $em;
        $this->router = $router;
    }

    public function onSecurityInteractiveLogin(InteractiveLoginEvent $event) 
    {
        $this->onAuthenticationSuccess($event->getRequest(), $event->getAuthenticationToken());
    }

    public function onAuthenticationSuccess(Request $request, TokenInterface $token) 
    {    
        $user = $token->getUser();
        $user->eraseCredentials();        
        $user->addRole('ROLE_USER');

        $this->em->flush() // If you don't do this, your changes will not be saved.
        $response = new RedirectResponse($this->router->generate('your_success_route'));

        return $response;
    }
}

Don't need of manually set the success_handler in your form, because the SuccessHandler is an EventListener and will be used on the corresponding event.

Community
  • 1
  • 1
chalasr
  • 12,971
  • 4
  • 40
  • 82
  • 1
    well it does not work either for me... onSecurityInteractiveLogin is not called... let's wait for some other people if it works for them – mlwacosmos Feb 26 '16 at 15:07
  • Very strange. Hope someone fix the problem. Don't forget to keep the code in your question same has your actual implementation. – chalasr Feb 26 '16 at 15:11
  • If you can, remove your whole listener to restart from zero and try this one https://gist.github.com/marydn/8061424 – chalasr Feb 26 '16 at 20:38
  • 1
    works when i change to "@doctrine.orm.default_entity_manager" in symfony 5 – Mitch May 16 '20 at 09:17
0

I don't know what the interactive login event is proposed here therefore I write a separate answer. @chalasr's answer worked for me but with security.authentication.success event:

login_success_handler:
    class:  YourBundle\EventListener\CustomAuthenticationSuccessHandler
    arguments:  ["@doctrine", "@router"]
    tags:
        - { name: kernel.event_listener, event: security.authentication.success, method: onAuthenticationSuccess }
code_gamer
  • 357
  • 5
  • 15