Monday, October 31, 2011

Set up an AuthenticationSuccessHandler in Symfony2

Symfony2 allows you to simply make treatments after a login attempt success. As simple as you just have to define a service, called "security.authentication.success_handler" and make it to implement AuthenticationSuccessHandlerInterface...

In this example, I want logged new user to be redirected to a "Terms and conditions" accept form. I have to check the boolean property termsAndConditionsOk of the User entity to know if redirection applies.
AuthenticationSuccessHandlerInterface defines 1 method :
<?php

/*
 * This file is part of the Symfony framework.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace Symfony\Component\Security\Http\Authentication;

use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\HttpFoundation\Request;

/**
 * Interface for a custom authentication success handler
 *
 * If you want to customize the success handling process, instead of
 * overwriting the respective listener globally, you can set a custom success
 * handler which implements this interface.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
interface AuthenticationSuccessHandlerInterface
{
    /**
     * This is called when an interactive authentication attempt succeeds. This
     * is called by authentication listeners inheriting from
     * AbstractAuthenticationListener.
     *
     * @param Request        $request
     * @param TokenInterface $token
     *
     * @return Response the response to return
     */
    function onAuthenticationSuccess(Request $request, TokenInterface $token);
}

Definition of the service in a services.yml config file (i use YAML) :

parameters:

    security.authentication.success_handler.class: Xxx\YourBundle\Component\OverSf2\Security\Http\Authentication\AuthenticationSuccessHandler

services:

    security.authentication.success_handler:
        class: %security.authentication.success_handler.class%
        public: false
        arguments:  ['@router', '@security.user.entity_manager']
And here is the AuthenticationSuccessHandler itself :
<?php

namespace Xxx\YouBundle\Component\OverSf2\Security\Http\Authentication;

use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\RouterInterface;
use Doctrine\ORM\EntityManager;
use Xxx\YourBundle\Entity\User;

/**
 * Custom authentication success handler
 */
class AuthenticationSuccessHandler implements AuthenticationSuccessHandlerInterface
{

   private $router;
   private $em;

   /**
    * Constructor
    * @param RouterInterface   $router
    * @param EntityManager     $em
    */
   public function __construct(RouterInterface $router, EntityManager $em)
   {
      $this->router = $router;
      $this->em = $em;
   }

   /**
    * This is called when an interactive authentication attempt succeeds. This
    * is called by authentication listeners inheriting from AbstractAuthenticationListener.
    * @param Request        $request
    * @param TokenInterface $token
    * @return Response The response to return
    */
   function onAuthenticationSuccess(Request $request, TokenInterface $token)
   {
      
      if (! $token->getUser()->getTermsAndConditionsOk())
      {
         $uri = $this->router->generate('_home');
      }
      else
      {
         $uri = $this->router->generate('_route_to terms_and_conditions_form');
      }

      return new RedirectResponse($uri);
   }
}

6 comments :

Anonymous said...

Hi,

i've take your solution, but myapp sf2 don't none when i'm login?

i've not create the route but i've not errors messages, just login perfectly.

i've just modify services.yml in my userbundle and add AuthenticationSuccessHandler controller in my userbundle

i miss anything ?

thanks

javigzz said...

I think you are missing, and the article above, is the configuration at security.yml:

security:
...
firewalls:
main:
form_login:
...
success_handler: security.authentication.success_handler


Otherwise the framework has no way to know about your service for this purpose.

regards

Javier

AlterPHP said...

security.authentication.success_handler is the default name for success_handler, as defined in the file vendor/symfony/symfony/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.xml.

So you're right to mention that, I will probably update my article. Thanks !

Glide said...

Note that it will override the default checks for redirection paths (like `use_referer`, `default_target_path`, ...)

Unknown said...

Didn't work for me without defining the handler in security.yml, as mentioned above:

form_login:
...
success_handler: security.authentication.success_handler

Thank you for this article, was really helpful!!!

Renato Chea said...

This post made my day!!! thank you very much, it was really helpfull!

Post a Comment

Comments are moderated before being published.