Paramètres

config.yml

app/config/config.yml contient la configuration des différents services et bundles. La configuration est paramétrée via le fichier parameters.yml, on a donc à priori peu de changements à y faire. J'ajoute ici les changements que j'ai déjà effectué.

Répertoire des sessions

On peut changer le répertoire où sont enregistrées les sessions. (Ne pas oublier de mettre les bons droits sur le dossier app/sessions)

framework:
    session:
        handler_id: session.handler.native_file
        save_path: "%kernel.root_dir%/sessions"

Enregistrement d'une commande

On peut créer ses propres commandes en ligne (http://symfony.com/doc/current/cookbook/console/console_command.html). On peut les enregistrer comme service alors dans le fichier de configuration.

services:
   app.command.my_command:
        class: MachinBundle\Command\MyCommand
        tags:
            -  { name: console.command }

Plusieurs bases de données

On peut vouloir utiliser plusieurs bases de données. (Les valeurs des paramètres sont biensûr entrées dans parameters.yml).

# app/config.yml
doctrine:
  dbal:
    default_connection: em1 # précise la connexion utilisée par défaut
    connections:
      em1:
        driver:   %database_driver%
        host:     %database_host%
        port:     %database_port%
        dbname:   %database_name1%
        user:     %database_user1%
        password: %database_password1%
        charset:  UTF8
      em2:
        driver:   %database_driver%
        host:     %database_host%
        port:     %database_port%
        dbname:   %database_name2%
        user:     %database_user2%
        password: %database_password2%
        charset:  UTF8

Et ensuite dans le controller on récupère le bon “entityManager” dans le controller comme suit:

    $em1 = $this->get('doctrine')->getEntityManager('em1');

parameters.yml

Le fichier app/config/parameters.yml contient la valeur des paramètres définis dans app/config/parameters.yml.dist. Lors d'un composer install ou update, le fichier parameters.yml est regénéré en faisant le diff entre la liste de paramètres dans les 2 fichiers.
Il faut donc éditer en premier app/config/parameters.yml.dist si on ajoute des paramètres!!

On peut enregistrer tous les paramètres souhaités, ainsi que des tableaux de paramètres.

parameters:
    database_driver: pdo_mysql
    database_host: 127.0.0.1
    database_port: null
    database_name: test
    database_user: root
    database_password: null
    mailer_transport: smtp
    mailer_host: null
    mailer_user: null
    mailer_password: null
    locale: fr
    secret: ThisTokenIsNotSoSecretChangeIt
    debug_toolbar: true
    debug_redirects: false
    use_assetic_controller: true
    webmaster: moi-même
    options:
        name:
            required: false
            display: true
        surname:
            required: true
            display: true

Pour y accéder dans un controller :

     $options = $this->container->getParameter('options');
     //ou plus court
     $options = $this->getParameter('options');

security.yml

le fichier de configuration

C'est ici que l'on peut définir tous les paramètres de sécurité. Les rôles et qui à droit à quoi. Quel entité pour l'authentification, Le cryptage… etc voir aussi en plus long : http://symfony.com/doc/current/reference/configuration/security.html

security:
    firewalls:
        secured_area:
            pattern:    ^/
            anonymous: ~
            http_basic:
                realm: "zone securisee"
            logout:
                path:   /logout
                target: /login
            form_login:
                login_path: /login
                check_path: /logincheck
                # par défaut, le formulaire de login *doit* être un POST,
                # et pas un GET
                post_only:                      true

                # options de redirection lorsque le login a réussi (vous
                # pouvez en lire plus ci-dessous)
                always_use_default_target_path: false
                default_target_path:            /restricted/
                target_path_parameter:          _target_path
                use_referer:                    false

                # options de redirection lorsque le login échoue (vous
                # pouvez en lire plus ci-dessous)
                failure_path:                   null
                failure_forward:                false

                # noms des champs pour le nom d'utilisateur et le mot
                # de passe
                username_parameter:             _username
                password_parameter:             _password
    role_hierarchy:
        ROLE_ADMIN: ROLE_CLIENT
        ROLE_SUPERADMIN: [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
    access_control:
        - { path: ^/restricted, roles: ROLE_ADMIN }
        - { path: ^/admin, roles: ROLE_SUPERADMIN }

    providers:
        administrators:
            entity: { class: MachinTrucBundle:Utilisateur, property: username }

    encoders:
        Machin\TrucBundle\Entity\Utilisateur:
            algorithm:        sha1
            encode_as_base64: false
            iterations:       1
Bien entendu, suppose qu'on a
  • une entité Utilisateur, avec username, password, roles…
  • une action login (accessible à tous dont l'url n'est pas du genre restricted/login mais bien login).
  • une action logincheck, en fait il faut juste une “route” dans le fichier routing.yml
  • logout n'est pas nécesssaire.
  • et quelque part, une méthode pour créer ces utilisateurs.

L'entité nécessaire

L'entité Utilisateur, on a forcément les propriétés username, password, salt, roles :

namespace Machin\TrucBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

use Symfony\Component\Security\Core\User\UserInterface;

class Utilisateur implements UserInterface, \Serializable
{
     private $username;
     private $password;
     private $salt;
     private $roles;
     private $isActive;
     
     ...
    public function __construct()
    {
        $this->isActive = true;
        //génère un grain de sel 
        $this->salt = md5(uniqid(null, true));
    }
    public function getRoles()
    {
    	$roles =array();
    	switch($this->roles){
    	//les rôles suivants sont inclusifs
	    case 'ROLE_SUPERADMIN':
	        $roles[]='ROLE_SUPERADMIN';
	    case 'ROLE_ADMIN':
		$roles[]='ROLE_ADMIN';
	    case 'ROLE_CLIENT':
	        $roles[]='ROLE_CLIENT';
	        break;
	}
    	return $roles;
    }
    
    public function serialize()
    {
       //important pour les performances 
       ...
    }
    
    public function unserialize()
    {
      ...
    }
}
Voir aussi http://symfony.com/doc/current/cookbook/security/entity_provider.html

Login et accès au User

Formulaire de login

namespace Machin\TrucBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Security\Core\SecurityContext;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;


class DefaultController extends Controller
{
	public function loginAction()
    {
        $request = $this->getRequest();
        $session = $request->getSession();
        //on récupère les erreurs de login
        if ($request->attributes->has(SecurityContext::AUTHENTICATION_ERROR)) {
            $error = $request->attributes->get(SecurityContext::AUTHENTICATION_ERROR);
        } else {
            $error = $session->get(SecurityContext::AUTHENTICATION_ERROR);
            $session->remove(SecurityContext::AUTHENTICATION_ERROR);
        }
        
        return $this->render('MachinTrucBundle:Default:login.html.twig', array(
            'last_pseudo' => $session->get(SecurityContext::LAST_USERNAME),
            'error' => $error
        ));
    }

Création d'un utilisateur

On a intérêt à créer un premier utilisateur(SUPERADMIN) avant de restreindre les droits d'accès.

 
namespace Machin\AdminBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class GestionController extends Controller
{
    public function AdduserAction(Request $request)
    {
        //Création d'un utilisateur
        $utilisateur = new Operateur();
	//Creation du formulaire  (suppose qu'on a créé une class UtilisateurType
	$form = $this->get('form.factory')->create(new UtilisateurType(), $utilisateur);
        
        // On fait le lien Requête <-> Formulaire (C'est ce qui est très bizarre!!)
        // À partir de maintenant, l'objet $utilisateur contient les valeurs entrées dans le formulaire.
        $form->handleRequest($request);
        if ($form->isValid()) {
              // On l'enregistre notre objet $utilisateur dans la base de données
              $factory = $this->get('security.encoder_factory');
              $salt =  md5(uniqid(null, true));
	      $utilisateur->setSalt($salt);
	      $encoder = $factory->getEncoder($utilisateur);
	      $password = $utilisateur->getPassword();
	      $password = $encoder->encodePassword($password, $salt);
	      $utilisateur->setPassword($password);
              $em->persist($utilisateur);
              $em->flush();
              //on redirige
              return $this->redirect($this->generateUrl('machin_admin_utilisateur'));
        }
        //sinon on affiche le formulaire
        return $this->render('MachinAdminBundle:Gestion:adduser.html.twig');
    }
}

Accès au user

    // Dans un controller
    // Pour récupérer les données de l'utilisateur authentifié
    $user = $this->get('security.context')->getToken()->getUser();
    //ou en plus court
    $user = $this->getUser();
    # dans une template 
    {{ app.security.getToken().getUser().getUsername() }}
    # en plus court
    {{ app.user.username}}
Suite - Librairie et Mises à jour