Symfony2 tutorial: Log a user manually by creating your own listener

I had to develop a user registration form with specific roles. The problem was that the form was too big and needed to be simplified.
I then decided to create my own bundle for multi-step registrations, and I needed to log a user manually after form registration, and I want to share what I’ve learned with you.

This is how you can perform it.
First of all, you have to know some symfony base principles:
– Current user informations are stored in the security context token, and, can be retrieved from here.
– The security context token listens to security interactiveLogin event that requires user object and token.

So, to log manually a user, we have to:
– create a user object and generate a token (we will use UsernamePasswordToken for that).
– Listen to interactiveLogin event and sends him the token with the current request
– Dispatch InteractiveLogin event to the security context.

Right, now let’s go!

Instead of creating a controller, we’ll create a listener “LoginListener” in a Listener directory.
This is how our code will looks like.

<?php

/**
 * Main docblock
 *
 * PHP version 5
 *
 * @category  Listener
 * @package   MultiStepFormsBundle
 * @author    Edouard Kombo <edouard.kombo@gmail.com>
 * @license   http://www.opensource.org/licenses/mit-license.php MIT License
 * @version   GIT: 1.0.0
 * @link      https://creativcoders.wordpress.com
 * @since     0.0.0
 */
namespace VendorName\UserBundle\Listener;

use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\SecurityContext;

/**
 * Listen to interactive login event and log in a user manually
 *
 * @category Listener
 * @package  MultiStepFormsBundle
 * @author   Edouard Kombo <edouard.kombo@gmail.com>
 * @license  http://www.opensource.org/licenses/mit-license.php MIT License
 * @link     https://creativcoders.wordpress.com
 */
class LoginListener
{
    /** 
     * @var \Symfony\Component\Security\Core\SecurityContext 
     */
    protected $securityContext;
        
    /**
     *
     * @var string $username
     */
    protected $username;
    
    /**
     *
     * @var object $em
     */
    protected $em;
    
    /**
     *
     * @var string $firewall
     */
    protected $firewall; 
    
    /**
     *
     * @var string $userEntity
     */
    protected $userEntity;     
    
    /**
     *
     * @var object $container
     */
    protected $container;    
    
    /**
     * Constructor
     * 
     * @param \Doctrine\ORM\EntityManager $em              Doctrine orm
     * @param object                      $container       Container Object
     * @param SecurityContext             $securityContext Security Management
     * 
     * @return \EdouardKombo\MultiStepFormsBundle\Listener\LoginListener
     */
    public function __construct(\Doctrine\ORM\EntityManager $em, $container, 
            SecurityContext $securityContext)
    {
        $this->em               = (object) $em; 
        $this->container        = (object) $container;
        $this->securityContext  = (object) $securityContext;
        
        return $this;
    }
    
    /**
     * Set the username
     * 
     * @param string $username Username of the current user
     * 
     * @return \EdouardKombo\MultiStepFormsBundle\Listener\LoginListener
     */
    public function setUsername($username)
    {
        $this->username = (string) $username;
        return $this;
    }
    
    /**
     * Set the firewall
     * 
     * @param string $firewall Actual security firewall
     * 
     * @return \EdouardKombo\MultiStepFormsBundle\Listener\LoginListener
     */
    public function setFirewall($firewall)
    {
        $this->firewall = (string) $firewall;
        return $this;
    }
    
    /**
     * Define the user entity
     * 
     * @param string $userEntity Project User entity
     * 
     * @return \EdouardKombo\MultiStepFormsBundle\Listener\LoginListener
     */
    public function setUserEntity($userEntity)
    {
        $this->userEntity = (string) $userEntity;
        return $this;
    }    
    
    /**
     * Login a user and dispatch the event.
     * 
     * @return object
     * @throws UsernameNotFoundException
     */
    public function secureInteractiveLogin()
    {
        if (!$this->securityContext->isGranted('IS_AUTHENTICATED_FULLY')) {
            
            $repository  = $this->em->getRepository($this->userEntity);       
            $user        = $repository->findOneByUsername($this->username);

            $request     = $this->container->get('request');
                
            if (!$user) {
                throw new UsernameNotFoundException("User not found");

            } else {
                //We need the name of the firewall
                $token = new UsernamePasswordToken($user, null, $this->firewall, 
                    $user->getRoles());

                $this->securityContext->setToken($token);

                //Now, login the user
                $event = new InteractiveLoginEvent($request, $token);
                return $this->container->get("event_dispatcher")->dispatch(
                    "security.interactive_login", 
                    $event
                );
            }            
        } else {
            $user = $event->getAuthenticationToken()->getUser();
        }
        
        return $user;
    }    
}

Last step is to create a service to inject dependencies on object construct.

//Change depending on your needs
services:
    multistep_forms.login_listener:
        class: %multistep_forms.login_listener.class%
        arguments:
            - @doctrine.orm.entity_manager
            - @service_container
            - @security.context
Advertisements
Symfony2 tutorial: Log a user manually by creating your own listener

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s