Symfony2: Authentification à partir d'une base de données

Publié le par hazamor

Cet exemple ci-dessous présente comment réaliser une authentification à partir d'une base de données avec Symfony2.

Prenons les deux entités "Admin" et  "Client" comme fornisseurs des utilisateurs.

Ces entités doivent implémenter les interfaces UserInterface et Serializable. Donc il faut définir les méthodes suivantes:

  • getRoles(): Retourne le role affecté à un utilisateur.

  • getPassword(): Retourne le mot de passe à utiliser lors de teste d'authentification.

  • getSalt(): Retourne une chaine de caractères à concaténer au mot de passe, si on a besoin.

  • getUsername(): Retourne le login à utiliser lors de teste d'authentification (ex: email, username,...).

  • eraseCredentials(): Supprimer les informations sensibles de l'entité.

  • equals(): Comparer les infromations de l'utilisateur à un autre utilisateur donné.
 
  namespace Hazem\SiteBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;
/**
* Hazem\SiteBundle\Entity\Admin * * @auther Hazem * @ORM\Table(name="admin") * @ORM\Entity(repositoryClass="Hazem\SiteBundle\Entity\AdminRepository") * @ORM\HasLifecycleCallbacks() */ class Admin implements UserInterface, \Serializable {
... function getRoles() { return array('ROLE_ADMIN'); }
function getUsername() { return $this->email; }

function getPassword() { return $this->motPasse; }

function getSalt() { return ''; }


function eraseCredentials() { $this->mot_de_passe = ''; }

function equals(UserInterface $user) { return ($user->getUsername() == $this->getUsername()); }

public function serialize() { return serialize(array($this->getUsername())); }

public function unserialize($serialized) { $arr = unserialize($serialized); $this->email = $arr[0];
}
... }

 

De même pour la 'repository' qui correspond à cette entity, elle doit implémenter l'interface 'UserProviderInterface'. Et donc les méthodes suivante:

  • loadUserByUsername(): Recoit un nom d'utilisateur et cherche les enregistrements qui lui correspond.
  • refreshUser(): Actualise les informations de l'utilisateur connecté.
  • supportsClass(): Recoit un nom de classe, et précise est ce que l'utilisateur connecté a comme type cette classe ou non.
 
namespace Hazem\SiteBundle\Entity;

use Doctrine\ORM\EntityRepository;
use Symfony\Component\Security\Core\User\UserProviderInterface;

class AdminRepository extends EntityRepository implements UserProviderInterface
{

public function loadUserByUsername($username) {
$admin = $this->getEntityManager()->getRepository('HazemSiteBundle:Admin')
->findOneBy(array(
'email' => $username
));
return $admin;
}

function refreshUser(UserInterface $user) {
return $this->loadUserByUsername($user->getUsername());
} function supportsClass($class){
return true;
}
...
}

 

Ensuite, vous devez créer les deux actions, l'une pour afficher le formulaire d'authentification et l'autre pour recevoir les informations envoyées et qui seront traiter automatiquement par symfony.

Dans le contrôlleur suivant, j'ai implémenté ces deux actions (login et check), avec une action pour la déconnexion et une autre pour rédiriger l'utilisateur selon son rôle:

 

 
namespace Hazem\SecurityBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Security\Core\SecurityContext;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Form\FormError;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;

/**
* @author hazem
*/
class SecuriteController extends Controller {

/**
* Afficher le formulaire d'authentification
* @Route("/login/", name="login")
* @Template()
* @param \Symfony\Component\HttpFoundation\Request $request
* @return Response
*/
public function loginAction() {
$request = $this->getRequest();
$session = $request->getSession();

if ($request->attributes->has(SecurityContext::AUTHENTICATION_ERROR)) {
$error = $request->attributes->get(SecurityContext::AUTHENTICATION_ERROR);
} else {
$error = $session->get(SecurityContext::AUTHENTICATION_ERROR);
}
if ($error)
$errorMessage = $error->getMessage();
else
$errorMessage='';
return array(
'last_username' => $session->get(SecurityContext::LAST_USERNAME),
'error_message' => $errorMessage,
);

}

/**
* Action pour recevoir les informations envoyées
* @Route("/login_check/", name="login_check")
* @author hazem
* @return \Symfony\Bundle\FrameworkBundle\Controller\RedirectResponse
*/
public function checkAction(Request $request) {
return new Response();
}

/**
* Deconnexion d'un utilisateur
* @Route("/logout/", name="logout")
* @author hazem
* @return \Symfony\Bundle\FrameworkBundle\Controller\RedirectResponse
*/
public function logoutAction() {
$session = $this->getRequest()->getSession();
$token = $session->get('token');

$this->get("request")->getSession()->invalidate();

$this->get("security.context")->setToken(null);

$this->getRequest()->getSession()->remove('token');

return $this->redirect($this->generateUrl('acceuil'));
}

/**
* redirection (selon le rôle) après une authentification avec succès
* @Route("/redirection/", name="redirection")
* @author hazem
* @return \Symfony\Bundle\FrameworkBundle\Controller\RedirectResponse
*/
public function redirectionAction() {
if ($this->get('security.context')->isGranted('ROLE_ADMIN'))
return $this->redirect($this->generateUrl('admin_acceuil'));

elseif ($this->get('security.context')->isGranted('ROLE_CLIENT'))
return $this->redirect($this->generateUrl('client_acceuil'));

}

}
 

L'action 'login' permet d'afficher un formulaire d'authentification.  Voilà un lien pour vous aider à créer un: http://symfony.com/doc/2.0/book/security.html#using-a-traditional-login-form

Maintenant, on doit configurer le système de sécurité. Dans le fichier security.yml, on doit préciser:

  • Les 'encoders' :description d'encodage de mot de passe d'une entité.
  • Les 'providers': les entités fournisseurs des utilisateurs.
  • Les 'firewalls': Les zones où la sécuirité de symfony est activée.
  • Les règles 'access_control': Association entre les urls et les droits nécessaires.
 
 security: encoders:
entity_admin: class: Hazem\SiteBundle\Entity\Admin algorithm: sha1 iterations: 1 encode_as_base64: false entity_client: class: Hazem\SiteBundle\Entity\Client
algorithm: sha1 iterations: 1
encode_as_base64: false
providers: chain_provider: providers: [entity_admin, entity_client] entity_admin: entity: class: Hazem\SiteBundle\Entity\Admin entity_client: entity: class: Hazem\SiteBundle\Entity\Client
firewalls: secured_area: pattern: /.* anonymous: ~ form_login: check_path: /securite/login_check/ login_path: /securite/login/ username_parameter: email password_parameter: motpasse always_use_default_target_path: true default_target_path: /securite/redirection logout: path: /securite/logout/ target: /
access_control: #- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY, requires_channel: https }

Vous voyez ici que 'login_path' et 'check_path' pointent sur les actions déjà créer dans SecuriteController.

Les deux instructions suivantes ont pour rôle de rédiriger l'utilisateur selon son rôle, soit qu'il arrive directment au page login , soit il demande un url protégé:

 

                always_use_default_target_path: true
                default_target_path: /securite/redirection

 

Pour sécuriser les urls, vous pouvez modifier 'access_control' dans security.yml, ou préciser le rôle nécessaire au niveau de l'action et avec les annotations, exemple:

 class AdminController extends Controller
{
/**
* @Route("/", name="admin_acceuil")
* @Template()
* @Secure(roles="ROLE_ADMIN")
*/
public function indexAction()
{
$user = $this->get('security.context')->getToken()->getUser();

return array('currentUser' => $user,
'page_menu_top'=>'acceuil',
'page_sub_menu_top'=>''
);
}
... }
 

 

Vous pouvez trouvez plus d'informations sur le système de sécurité de symfony2 ici:

http://symfony.com/doc/2.0/book/security.html

http://symfony.com/doc/2.0/reference/configuration/security.html

http://symfony.com/doc/2.0/cookbook/security/form_login.html

Pour être informé des derniers articles, inscrivez vous :
Commenter cet article
H
Cleaning up services NEW YORK CITY will cleanse exhaust fans fairly often. Exhaust admirers become clogged and make fire hazards once they are never maintained accurately. With your cleaning company, Dubai Urban center restaurants might be in tip-top contour because but not only will people clean fatigue fans however will tension wash floors together with the restaurant outer. They is going to mop plus wax floorings, empty oil traps, and sterilize bathrooms for a regular eaterie cleaning agenda.
Répondre
H
Cleaning up services NEW YORK CITY will cleanse exhaust fans fairly often. Exhaust admirers become clogged and make fire hazards once they are never maintained accurately. With your cleaning company, Dubai Urban center restaurants might be in tip-top contour because but not only will people clean fatigue fans however will tension wash floors together with the restaurant outer. They is going to mop plus wax floorings, empty oil traps, and sterilize bathrooms for a regular eaterie cleaning agenda.
Répondre
M
Bonjour,<br /> Est ce que la même chose avec symfony3?
Répondre
M
Bonjour,<br /> j'ai une erreur qui est la suivante:<br /> Compile Error: Declaration of TakwaBundle\Repository\AdminRepository::refreshUser() must be compatible with Symfony\Component\Security\Core\User\UserProviderInterface::refreshUser(Symfony\Component\Security\Core\User\UserInterface $user)<br /> merci d'avance de vos aides
Répondre
M
Bon article ! Juste que tu pourrais utiliser les gists de Github pour afficher ton code, il sera correctement affiché ;) (si tu peux bien sûr ^^)<br /> <br /> Bonne continuation dans SF2
Répondre