You are on page 1of 17

Sans titre

Les fichier modifier a remplacer


security.yaml
security:
enable_authenticator_manager: true
# https://symfony.com/doc/current/security.html#registering-the-user-hashing-
passwords
password_hashers:
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
# https://symfony.com/doc/current/security.html#loading-the-user-the-user-
provider
providers:
# used to reload user from session & other features (e.g. switch_user)
app_user_provider:
entity:
class: App\Entity\User
property: email
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
lazy: true
provider: app_user_provider
# custom_authenticator: App\Security\AppAuthenticator
form_login:
login_path: app_login
check_path: app_login
logout:
path: app_logout
# where to redirect after logout
# target: app_any_route
# activate different ways to authenticate
# https://symfony.com/doc/current/security.html#the-firewall

# https://symfony.com/doc/current/security/impersonating_user.html
# switch_user: true

# Easy way to control access for large sections of your site


# Note: Only the *first* access control that matches will be used
access_control:
- { path: ^/admin, roles: ROLE_ADMIN }
- { path: ^/profil, roles: ROLE_USER }
when@test:
security:
password_hashers:
# By default, password hashers are resource intensive and take time. This is
# important to generate secure password hashes. In tests however, secure hashes
# are not important, waste resources and increase test times. The following
# reduces the work factor to the lowest possible values.
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface:
algorithm: auto
cost: 4 # Lowest possible value for bcrypt
time_cost: 3 # Lowest possible value for argon
memory_cost: 10 # Lowest possible value for argon

src/controller/SecurityController.php
<?php

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;

class SecurityController extends AbstractController


{
#[Route(path: '/login', name: 'app_login')]
public function login(AuthenticationUtils $authenticationUtils): Response
{
// if ($this->getUser()) {
// return $this->redirectToRoute('target_path');
// }

// get the login error if there is one


$error = $authenticationUtils->getLastAuthenticationError();
// last username entered by the user
$lastUsername = $authenticationUtils->getLastUsername();

return $this->render('security/login.html.twig', ['last_username' =>


$lastUsername, 'error' => $error]);
}

#[Route(path: '/logout', name: 'app_logout')]


public function logout(): void
{
throw new \LogicException('This method can be blank - it will be intercepted by
the logout key on your firewall.');
}
}

src/entity/user.php ( qui demandera surement un migration de la base )


<?php

namespace App\Entity;

use Assert\Email;
use Assert\NotBlank;
use Doctrine\ORM\Mapping as ORM;
use App\Repository\UserRepository;
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\component\Uid\Uuid;

use
Symfony\Component\Security\Core\Utilisateur\PasswordAuthenticatedUtilisateurInter
face;
use App\Repository\UtilisateurRepository;
use App\Entity\UtilisateurInterface;

#[ORM\Entity(repositoryClass: UserRepository::class)]
#[UniqueEntity('email', 'Cet email existe déjà au sein de l\'application.')]
class User implements UserInterface, PasswordAuthenticatedUserInterface
{
#[ORM\Id]
#[ORM\GeneratedValue('CUSTOM')]
#[ORM\Column(type: 'uuid', unique: true)]
#[ORM\CustomIdGenerator('doctrine.uuid_generator')]
private ?string $id = null;

#[ORM\Column(type: 'string', length: 255, nullable: true)]


private string $avatar;

#[ORM\Column(type: 'string', length: 255, unique: true)]


#[Assert\NotBlank()]
#[Assert\Email()]
private string $email;

#[ORM\Column(type: 'string', length: 255, nullable: true)]


private ?string $lastName = null;

#[ORM\Column(type: 'string', length: 255, nullable: true)]


private ?string $firstName = null;
#[ORM\Column(type: 'json')]
private array $roles = ['ROLE_USER'];

/**
* @var string The hashed password
*/
#[ORM\Column]
private ?string $password = null;

#[ORM\Column(length: 255, nullable: true)]


private ?string $userAdminSlug = null;

#[ORM\OneToMany(mappedBy: 'userAdmin', targetEntity: Video::class)]


private Collection $videos;

#[ORM\OneToMany(mappedBy: 'userAdmin', targetEntity: Marker::class)]


private Collection $markers;

#[ORM\OneToMany(mappedBy: 'userAdmin', targetEntity: ArticlesBlog::class)]


private Collection $articlesBlogs;

#[ORM\Column(type: 'boolean')]
private $isVerified = false;

#[ORM\Column(type: 'datetime_immutable')]
#[Assert\NotNull()]
private \DateTimeImmutable $createdAt;

#[ORM\Column(type: 'datetime_immutable')]
#[Assert\NotNull()]
private \DateTimeImmutable $updatedAt;

public function __construct()


{
$this->videos = new ArrayCollection();
$this->markers = new ArrayCollection();
$this->articlesBlogs = new ArrayCollection();
$this->createdAt = new \DateTimeImmutable();
$this->updatedAt = new \DateTimeImmutable();
}

#[ORM\PrePersist]
public function prePersist(): void
{
$this->avatar = 'https://api.dicebear.com/7.x/lorelei-neutral/svg' . $this->email
. '.svg';
}

#[ORM\PreUpdate]
public function preUpdate(): void
{
$this->avatar = 'https://api.dicebear.com/7.x/lorelei-neutral/svg' . $this->email
. '.svg';
$this->updatedAt = new \DateTimeImmutable();
}

public function getId(): ?string


{
return $this->id;
}

public function getAvatar(): string


{
return $this->avatar;
}

public function getEmail(): string


{
return $this->email;
}

public function setEmail(string $email): self


{
$this->email = $email;

return $this;
}

public function getLastName(): ?string


{
return $this->lastName;
}

public function setLastName(?string $lastName): self


{
$this->lastName = $lastName;

return $this;
}

public function getFirstName(): ?string


{
return $this->firstName;
}

public function setFirstName(?string $firstName): self


{
$this->firstName = $firstName;

return $this;
}
// public function getUserAdminName(): ?string
// {
// return $this->userAdminName;
// }

// public function setUserAdminName(string $userAdminName): static


// {
// $this->userAdminName = $userAdminName;
//
// return $this;
// }

/**
* A visual identifier that represents this user.
*
* @see UserInterface
*/
public function getUserIdentifier(): string
{
return (string) $this->email;
}

/**
* @deprecated since Symfony 5.3, use getUserIdentifier instead
*/
public function getUsername(): string
{
return (string) $this->email;
}

/**
* @see UserInterface
*/
public function getRoles(): array
{
$roles = $this->roles;
// guarantee every user at least has ROLE_USER
$roles[] = 'ROLE_USER';

return array_unique($roles);
}

public function setRoles(array $roles): static


{
$this->roles = $roles;

return $this;
}

/**
* @see PasswordAuthenticatedUserInterface
*/
public function getPassword(): string
{
return $this->password;
}

public function setPassword(string $password): static


{
$this->password = $password;

return $this;
}

/**
* Returning a salt is only needed, if you are not using a modern
* hashing algorithm (e.g. bcrypt or sodium) in your security.yaml.
*
* @see UserInterface
*/
public function getSalt(): ?string
{
return null;
}

/**
* @see UserInterface
*/
public function eraseCredentials(): void
{
// If you store any temporary, sensitive data on the user, clear it here
// $this->plainPassword = null;
}

public function getUserAdminSlug(): ?string


{
return $this->userAdminSlug;
}

public function setUserAdminSlug(string $userAdminSlug): static


{
$this->userAdminSlug = $userAdminSlug;

return $this;
}

/**
* @return Collection<int, Video>
*/
public function getVideos(): Collection
{
return $this->videos;
}

public function addVideo(Video $video): static


{
if (!$this->videos->contains($video)) {
$this->videos->add($video);
$video->setUserAdmin($this);
}

return $this;
}

public function removeVideo(Video $video): static


{
if ($this->videos->removeElement($video)) {
// set the owning side to null (unless already changed)
if ($video->getUserAdmin() === $this) {
$video->setUserAdmin(null);
}
}

return $this;
}

/**
* @return Collection<int, Marker>
*/
public function getMarkers(): Collection
{
return $this->markers;
}

public function addMarker(Marker $marker): static


{
if (!$this->markers->contains($marker)) {
$this->markers->add($marker);
$marker->setUserAdmin($this);
}

return $this;
}

public function removeMarker(Marker $marker): static


{
if ($this->markers->removeElement($marker)) {
// set the owning side to null (unless already changed)
if ($marker->getUserAdmin() === $this) {
$marker->setUserAdmin(null);
}
}
return $this;
}

/**
* @return Collection<int, ArticlesBlog>
*/
public function getArticlesBlogs(): Collection
{
return $this->articlesBlogs;
}

public function addArticlesBlog(ArticlesBlog $articlesBlog): static


{
if (!$this->articlesBlogs->contains($articlesBlog)) {
$this->articlesBlogs->add($articlesBlog);
$articlesBlog->setAAUserAdmin($this);
}

return $this;
}

public function removeArticlesBlog(ArticlesBlog $articlesBlog): static


{
if ($this->articlesBlogs->removeElement($articlesBlog)) {
// set the owning side to null (unless already changed)
if ($articlesBlog->getAAUserAdmin() === $this) {
$articlesBlog->setAAUserAdmin(null);
}
}

return $this;
}

public function isVerified(): bool


{
return $this->isVerified;
}

public function setIsVerified(bool $isVerified): static


{
$this->isVerified = $isVerified;

return $this;
}
}

registrationFormType a modifier
<?php

namespace App\Form;

use App\Entity\User;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\TextType; // N'oublie pas
d'ajouter cette ligne
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\IsTrue;
use Symfony\Component\Validator\Constraints\Length;
use Symfony\Component\Validator\Constraints\NotBlank;

class RegistrationFormType extends AbstractType


{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('email')

->add('firstName', TextType::class, [ // Ajoute ce bloc pour le champ prénom


'label' => 'Prénom',
'required' => false,
'constraints' => [
new NotBlank([
'message' => 'Veuillez entrer un prénom',
]),
new Length([
'max' => 255,
]),
],
])

->add('lastName', TextType::class, [ // Ajoute ce bloc pour le champ nom


'label' => 'Nom',
'required' => false,
'constraints' => [
new NotBlank([
'message' => 'Veuillez entrer un nom',
]),
new Length([
'max' => 255,
]),
],
])
->add('agreeTerms', CheckboxType::class, [
'label'=>"J'accepte les conditions d'utilisation",
'mapped' => false,
'constraints' => [
new IsTrue([
'message' => 'You should agree to our terms.',
]),
],
])
->add('plainPassword', PasswordType::class, [
'mapped' => false,
'constraints' => [
new NotBlank([
'message' => 'Please enter a password',
]),
new Length([
'min' => 6,
'minMessage' => 'Your password should be at least {{ limit }} characters',
'max' => 4096,
]),
],
])
;
}

public function configureOptions(OptionsResolver $resolver): void


{
$resolver->setDefaults([
'data_class' => User::class,
]);
}
}

les templates
template/security/
login.html.twig
{% extends 'base.html.twig' %}

{% block stylesheets %}
<link rel="stylesheet" href="{{ asset('css/styles.css') }}">
{% endblock %}

{% block title %}Connexion{% endblock %}


{% block body %}
<div class="login-container">
<form action="" method="POST">
<h2>Connexion</h2>
<div class="form-group">
<label for="username">Nom d'utilisateur</label>
<input type="text" id="username" name="_username" required />
</div>
<div class="form-group">
<label for="password">Mot de passe</label>
<input type="password" id="password" name="_password" required />
</div>
<div class="form-group">
<button type="submit">Se connecter</button>
</div>
</form>
</div>
{% endblock %}

admin_login.html.twig
{% extends 'base.html.twig' %}

{% block stylesheets %}
<link rel="stylesheet" href="{{ asset('css/admin-styles.css') }}">
{% endblock %}

{% block title %}Admin - Connexion{% endblock %}

{% block body %}
<div class="admin-login-container">
<form action="" method="POST">
<h2>Admin - Connexion</h2>
<div class="admin-form-group">
<label for="username">Nom d'utilisateur</label>
<input type="text" id="username" name="_username" required />
</div>
<div class="admin-form-group">
<label for="password">Mot de passe</label>
<input type="password" id="password" name="_password" required />
</div>
<div class="admin-form-group">
<button type="submit" class="admin-button">Se connecter</button>
</div>
</form>
</div>
{% endblock %}
le css j'ai ajouter deux fichier juste mais ca tu peut le changer ( public/css/
styles.css et admin-styles.csss
styles.css
body {
font-family: 'Arial, sans-serif';
background-color: #f0f0f0;
}

.login-container {
width: 300px;
margin: 100px auto;
background-color: #fff;
padding: 20px;
border-radius: 5px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}

.login-container h2 {
margin-bottom: 20px;
text-align: center;
font-size: 24px;
color: #333;
}

.login-container .form-group {
margin-bottom: 15px;
}

.login-container .form-group label {


display: block;
margin-bottom: 5px;
font-weight: bold;
color: #333;
}

.login-container .form-group input {


width: 100%;
padding: 10px;
border: 1px solid #ccc;
border-radius: 5px;
font-size: 16px;
}

.login-container .form-group button {


width: 100%;
border: none;
border-radius: 5px;
font-size: 16px;
background-color: #007BFF;
color: #fff;
cursor: pointer;
}

.login-container .form-group button:hover {


background-color: #0056b3;
}

/* */

.register-container {
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
background-color: #f4f4f4;
}

.register-form {
width: 300px;
background-color: #fff;
padding: 20px;
border-radius: 10px;
box-shadow: 0 0 10px rgba(0,0,0,0.1);
}

.form-group {
margin-bottom: 1rem;
}
.form-group label {
display: inline-block;
width: 100%;
text-align: center;
margin-bottom: 8px;
font-weight: bold;
}

.form-group input {
display: block;
width: 100%;
padding: 10px;
margin: 0 auto;
border: 1px solid #ccc;
border-radius: 4px;
}

button[type="submit"] {
display: block;
margin: 0 auto;
padding: 10px 20px;
background-color: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}

admin-styles.csss
.admin-login-container {
width: 400px;
margin: auto;
border: 1px solid #ccc;
border-radius: 10px;
padding: 20px;
background-color: #f9f9f9;
}

.admin-form-group {
margin-bottom: 15px;
}

.admin-form-group label {
font-weight: bold;
display: block;
margin-bottom: 5px;
}

.admin-form-group input {
width: 100%;
padding: 10px;
border: 1px solid #ccc;
border-radius: 5px;
}

.admin-button {
background-color: #007bff;
color: white;
padding: 10px 20px;
border: none;
border-radius: 5px;
cursor: pointer;
}

.admin-button:hover {
background-color: #0056b3;
}

template/registration/register.html.twig
{% extends 'base.html.twig' %}

{% block stylesheets %}
<link rel="stylesheet" href="{{ asset('css/styles.css') }}">
{% endblock %}

{% block title %}Inscription{% endblock %}

{% block body %}
<div class="register-container">
<form class="register-form" method="POST">
<h2>Inscription</h2>
{% for flash_error in app.flashes('verify_email_error') %}
<div class="alert alert-danger" role="alert">{{ flash_error }}</div>
{% endfor %}
{{ form_errors(registrationForm) }}
{{ form_start(registrationForm) }}
<div class="form-group">
{{ form_label(registrationForm.email) }}
{{ form_widget(registrationForm.email) }}
</div>
<div class="form-group">
{{ form_label(registrationForm.plainPassword) }}
{{ form_widget(registrationForm.plainPassword) }}
</div>
<div class="form-group">
{{ form_label(registrationForm.firstName, 'Prénom') }}
{{ form_widget(registrationForm.firstName) }}
</div>
<div class="form-group">
{{ form_label(registrationForm.lastName, 'Nom') }}
{{ form_widget(registrationForm.lastName) }}
</div>
<div class="form-group">
{{ form_label(registrationForm.agreeTerms, "J'accepte les conditions
d'utilisation") }}
{{ form_widget(registrationForm.agreeTerms) }}
</div>
<div class="form-group">
<button type="submit">S'inscrire</button>
</div>
{{ form_end(registrationForm) }}
</form>
</div>
{% endblock %}

penser aussi au AAUserFixtures


dans src/DataFixture
<?php

namespace App\DataFixtures;

use App\Entity\User;
use Doctrine\Persistence\ObjectManager;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;

class AAUserFixtures extends Fixture


{
private $encoder;
public function __construct(UserPasswordHasherInterface $encoder)
{
$this->encoder = $encoder;
}

public const USER_ADMIN_NAME = 'user-admin-name';

public function load(ObjectManager $manager): void


{
$user = new User();
$user->setEmail("habibata-doucoure@hotmail.fr");
$user->setPassword($this->encoder->hashPassword($user,'passlo'));
$user->setUserAdminSlug("violence0");
$user->setRoles(['ROLE_ADMIN']);
$user->setIsVerified(true);
$manager->persist($user);
$this->addReference(self::USER_ADMIN_NAME, $user);

$manager->flush();
}
}

You might also like