security manager : introduction

Présentation de l’authentification sur symfony https://openclassrooms.com/courses/developpez-votre-site-web-avec-le-framework-symfony2/securite-et-gestion-des-utilisateurs

https://openclassrooms.com/fr/courses/5489656-construisez-un-site-web-a-l-aide-du-framework-symfony-4/5654131-securisez-lacces-de-votre-site-web

openclassroom (doc symfony)
openclassroom (doc symfony)


openclassroom
openclassroom

Dans la structure security (configuration du security manager) :

contrôleur pour tester le security manager

<?php

namespace App\Controller;

use Symfony\Component\Routing\Annotation\Route;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;

use Symfony\Component\HttpFoundation\Request;

class IndexController extends AbstractController
{
    /**
     * @Route("/", name="index_index")
     */
    public function index(Request $request)
    {

//        if(! is_null($this->getUser())){
//            echo "<br>";
//            echo " id: ".$this->getUser()->getId();
//            echo " roles :   ";
//            print_r($this->getUser()->getRoles());
//            die();
//        }

        if($this->isGranted('ROLE_ADMIN')) {
            return $this->redirectToRoute('admin_produit_index');
            // return $this->render('admin/produit/showProduits.html.twig');
        }
        if($this->isGranted('ROLE_CLIENT')) {
            return $this->redirectToRoute('client_panierSession_index');
            //  return $this->render('client/boutique/produit.html.twig');
        }
        return $this->render('accueil.html.twig');

    }
}
<?php
namespace App\Controller\Client;

use App\Entity\Produit;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;

class PanierSessionController extends AbstractController
{

    /**
     * @Route("/client", name="client_panierSession_index", methods={"GET"})
     * @Route("/client/produits/show", name="client_panierSession_showProduits", methods={"GET"})
     */
    public function showPanierSessionProduits(Request $request)
    {
        $produits = $this->getDoctrine()->getRepository(Produit::class)->findBy([], ['typeProduit' => 'ASC', 'stock' => 'ASC']);
        return $this->render('client/boutique/panier_produit.html.twig', ['produits' => $produits]);
    }
}


Création des utilisateurs

Il faut suivre la Documentation : https://symfony.com/doc/master/security.html

php bin/console make:user
The name of the security user class (e.g. User) [User]:
> User

Do you want to store user data in the database (via Doctrine)? (yes/no) [yes]:
> yes

Enter a property name that will be the unique "display" name for the user (e.g.
email, username, uuid [email]
> 

username

Does this app need to hash/check user passwords? (yes/no) [yes]:
> yes

created: src/Entity/User.php
created: src/Repository/UserRepository.php
updated: src/Entity/User.php
updated: config/packages/security.yaml

modification de l’entité User

    // ********************************

    /**
     * @ORM\Column(type="string", length=60, unique=true)
     */
    private $email;

    /**
     * @ORM\Column(name="is_active", type="boolean")
     */
    private $isActive;


    /**
     * @ORM\Column(type="string", nullable=true)
     */
    private $nom = '';

    /**
     * @ORM\Column(type="string", nullable=true)
     */
    private $ville = '';

    /**
     * @ORM\Column(type="string", nullable=true)
     */
    private $codePostal = '';

    /**
     * @ORM\Column(type="string", nullable=true)
     */
    private $adresse = '';

    /**
     * @ORM\Column(type="string", nullable=true)
     */
    private $tokenMail = '';

    public function __toString()
    {
        // TODO: Implement __toString() method.
        return "username : ".$this->getUsername()." role: ".$this->getRoles()[0]." mdp:".$this->getPassword();
    }

    public function __construct()
    {
        $this->isActive = true;
    }
php bin/console make:entity --regenerate
php bin/console doctrine:schema:update --force

ajouter des Utilisateurs dans les fixtures

use App\Entity\User;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;

.....
private $passwordEncoder;

public function __construct(UserPasswordEncoderInterface $passwordEncoder)
{
    $this->passwordEncoder = $passwordEncoder;
}

// appeler la méthode loadUsers dans la méthode load

    public function loadUsers(ObjectManager $manager)
    {
        echo " \n\nles utilisateurs : \n";

        $admin = new User();
        $password = $this->passwordEncoder->encodePassword($admin, 'admin');
        $admin->setPassword($password);
        $admin->setRoles(['ROLE_ADMIN'])
            ->setUsername('admin')->setEmail('admin@example.com')->setIsActive('1');
        $manager->persist($admin);
        echo $admin."\n";

        $client = new User();
        $password = $this->passwordEncoder->encodePassword($client, 'client');
        $client->setPassword($password);
        $client->setRoles(['ROLE_CLIENT'])->setUsername('client')
            ->setEmail('client@example.com')->setIsActive('1');
        $manager->persist($client);
        echo $client."\n";

        $client2 = new User();
        $password = $this->passwordEncoder->encodePassword($client, 'client2');
        $client2->setPassword($password);
        $client2->setRoles(['ROLE_CLIENT'])->setUsername('client2')
            ->setEmail('client2@example.com')->setIsActive('1');
        $manager->persist($client2);
        echo $client2."\n";

        $manager->flush();
    }
php bin/console doctrine:fixtures:load
bin/console doctrine:query:sql "select * from user;"
bin/console security:encode-password admin

mise en place de la sécurité

Dans symfony, un assistant permet de gagner beaucoup de temps si on désire une authentification basique


Suivre la documentation symfony https://symfony.com/doc/current/security/form_login_setup.html

 php bin/console make:auth

What style of authentication do you want? [Empty authenticator]:
 [0] Empty authenticator
 [1] Login form authenticator
> 1

The class name of the authenticator to create (e.g. AppCustomAuthenticator):
> LoginFormAuthenticator
...
{% extends 'layout_home.html.twig' %}



tester

il faut modifier le fichier src/Security/LoginFormAuthenticator.php et ajouter :

return new RedirectResponse($this->urlGenerator->generate('index_index'));

access_control (firewalls et routes)


Le plus important : sécuriser les routes et les classes

https://symfony.com/doc/current/security.html#firewalls-authentication

sécuriser les routes

security:
# .......
    access_control:
        - { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/register, roles: IS_AUTHENTICATED_ANONYMOUSLY }
        #- { path: ^/, roles: [ROLE_USER, ROLE_CLIENT] }
        - { path: ^/client, roles: ROLE_CLIENT }
        - { path: ^/admin, roles: ROLE_ADMIN }

sécuriser les classes

use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;

/**
 * devant la Class AdminController
 * @IsGranted("ROLE_ADMIN")
 */

Attention aux majuscules et minuscules des mots clés (nom des objets et des méthodes) !!


il est possible de mettre des restrictions directement dans le code https://symfony.com/doc/master/security.html#securing-controllers-and-other-code

dans les vues

{% if is_granted('ROLE_ADMIN') %}
    <a href="...">Delete</a>
{% endif %}
{% if is_granted('IS_AUTHENTICATED_FULLY') %}
    <p>Email: {{ app.user.email }}</p>
{% endif %}
    {% if is_granted('IS_AUTHENTICATED_FULLY') %}
        <p> Bonjour Username: {{ app.user.username }}</p> {% if is_granted('ROLE_ADMIN') %} (role : Admin ) <br>{% endif %}
        {% if is_granted('ROLE_USER') %} (role : User ) <br>{% endif %}
        <a href="{{ path('app_logout') }}"> deconnexion</a><br>
    {% else %}
        <a href="{{ path('app_login') }}"> se connecter</a><br>
    {% endif %}

dans les contrôleurs

voir exemple dans IndexController.php pour récupérer l’identifiant de l’utilisateur connecté https://symfony.com/doc/current/security.html#a-fetching-the-user-object

        if(! is_null($this->getUser())){
            echo "<br>";
            echo " id: ".$this->getUser()->getId();
            echo " roles :   ";
            print_r($this->getUser()->getRoles());
            die();
        }

hiérarchie des rôles

http://symfony.com/doc/current/security/access_control.html

dans le bloc security, ajouter au ROLE_USER les droits de ROLE_ADMIN

security:
#.....
    role_hierarchy:
        ROLE_USER:       ROLE_ADMIN
        ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]

se créer un compte

https://symfony.com/doc/4.2/doctrine/registration_form.html

message d’erreur personnalisé

utiliser la documentation ci-dessous pour configurer le message d’erreur (très facile)

https://symfony.com/doc/current/security/access_denied_handler.html



















ANNEXES :

https://www.youtube.com/watch?v=_GjHWa9hQic&feature=youtu.be

erreurs possibles

fichier config/routes.yaml , ne pas oublier

logout:
    path: /logout
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;

/**
 * devant la Class AdminController
 * @Security("has_role('ROLE_ADMIN')")
 */