Symfony2: Connexion automatique avec FosUserBundle

En général, la connexion avec FosUserBundle se fait à travers un formulaire, mais récemment j’avais besoin d’une tâche pas assez récurrente, dans ce cas l’utilisateur peut se connecter automatiquement en cliquant sur un lien envoyé par email.

Tout d’abord, j’ai ajouté à ma entité User un attribut qui va jouer le rôle d’un jeton de connexion, ce jeton est généré automatiquement lors de la persiste de l’objet User via les events PrePersist et PreUpdate :


use FOS\UserBundle\Model\User as BaseUser;

/**
 * User
 *
 * @ORM\Table(name="users")
 * @ORM\Entity(repositoryClass="Nm\UserBundle\Repository\UserRepository")
 * @ORM\HasLifecycleCallbacks
 */
class User extends BaseUser
{
     // ...

    /**
     * @var string
     * @ORM\Column(name="login_token", type="string", length=255, unique=true)
     */
    private $loginToken;

    /**
     * @ORM\PrePersist()
     * @ORM\PreUpdate()
     */
    public function preUpload()
    {
        if (null === $this->loginToken) {
            $this->loginToken = sha1(uniqid(mt_rand(), true));
        }
    }
}

Après, j’ai créé l’action de la connexion automatique, sa route prendra en paramètre le loginToken :


use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;

//...

    /**
     * @Route("/auto-login/{loginToken}", name="auto_login")
     */
    public function autoLogin(Request $request, User $user)
    {
         $firewallName = $this->container->getParameter('fos_user.firewall_name');
        
        $token = new UsernamePasswordToken($user, $user->getPassword(), $firewallName, $user->getRoles());
        $this->get('security.context')->setToken($token);
        $request->getSession()->set('_security_main', serialize($token));
        $url = $this->generateUrl('fos_user_registration_confirmed');
        $response = new RedirectResponse($url);
                    
        return $response;
    }

[Symfony2] Collection des Bundles pour accélérer votre développement

Depuis la naissance de Symfony2, un grand nombre de bundles ont été créés pour faciliter la tâche au développeurs.
Voici ma collection des bundles indispensable pour chaqu’un de mes projets Symfony :

1. FOSUserBundle : un bundle pour la gestion des utilisateurs, il implémente beaucoup de fonctionnalités tel que inscription, authentification, récupération mot de passe …

2. DoctrineExtensions : un bundle très pratique intègre une série d’extensions Doctrine comme Sluggable, Translatable, Timetampable, Sortable …

3. KnpPaginatorBundle : un système de pagination simple d’utilisation et performant.

4. GenemuFormBundle : Bundle Symfony plein de FormType à insérer dans les formulaires. il facilite l’utilisation des champs de formulaire de type Select2, tinyMCE, ReCaptcha, Rating …

5. KnpMenuBundle : c’est un Bundle qui permet de gérer assez facilement les menus d’un site web. Faire un menu statique est très simple, mais parfois, le développeur a besoin de construire un menu (ou un sous-menu) en fonction de contenus en base de données. Ce Bundle va donc vous être très utile.

[Symfony2][FOSUserBundle] Utiliser l’adresse mail pour se connecter

FOSUserBundle a son propre provider pour que vous pouvez utiliser non seulement le nom d’utilisateur, mais aussi l’email pour ce connecter. Il suffit de changer une ligne dans security.yml


# app/config/security.yml
security:
    providers:
        fos_userbundle:
            id: fos_user.user_provider.username_email

Par contre si vous voulez utiliser seulement l’adresse mail pour se connecter, il faut passer par une autre méthode. Selon la documentation d’une ancienne version de FosUserBundle, la méthode le plus « propre » et la moins risquer et de passer par un provider personnalisé.


<?php
namespace FOS\UserBundle\Security;

class EmailUserProvider extends UserProvider
{
    protected function findUser($username)
    {
        return $this->userManager->findUserByUsernameOrEmail($username);
    }
}

Comme vous pouvez remarquer notre provider personnalisé hérite de celui de FosUserBundle, et on a surchargé seulement une seule méthode.

Maintenant, nous allons l’ajouter comme un service à notre application :


<parameters>
    <parameter key="gmu.user_provider.email.class">Gmu\UserBundle\Security\GmuUserProvider</parameter>
  </parameters>
  <services>
    <service id="gmu.user_provider.email">
      <argument type="service" id="fos_user.user_manager" />
    </service>
  </services>

Nous avons injecté FOSUserManager parce que la classe parente en a besoin. Après cela, nous indiquant qu’on va utiliser notre service comme le provider par défaut :


# app/config/security.yml
security:
    providers:
        fos_userbundle:
            id: gmu.user_provider.email