简体   繁体   English

Symfony 3-如何通过bcrypt加密的密码对用户进行身份验证?

[英]Symfony 3 - How to authenticate a user from a password encrypted by bcrypt?

I have a User entity, with password encryption by bcrypt, in the database. 我在数据库中有一个User实体,通过bcrypt进行了密码加密。

In fact, when a user is created, I generate a random password of 7 characters, and send him by mail. 实际上,创建用户时,我会生成7个字符的随机密码,然后通过邮件发送给他。 This password is encrypted using bcrypt and then in the database in the password attribute. 使用bcrypt对该密码进行加密,然后在数据库的password属性中进行加密。

I would like that when my user connects from my login form, he can enter the password that I sent him by email to authenticate. 我希望当用户从我的登录表单连接时,他可以输入我通过电子邮件发送给他的密码以进行身份​​验证。 But I do not understand how to do it. 但是我不知道该怎么做。 I can look at different sites, I do not see. 我可以看不同的站点,看不到。

In addition, I think my code is a little mess ... My ultimate goal being to authenticate the user, so he has an open session, with a possibility to disconnect, and it is restricted to certain pages. 此外,我认为我的代码有些混乱……我的最终目标是对用户进行身份验证,因此他具有打开的会话,可以断开连接,并且仅限于某些页面。 But also to manage if the user is activated, and its expiration date. 而且还可以管理用户是否被激活及其有效期。

I emphasize the fact that I am a beginner in symfony (I discovered it 2 weeks ago as part of my internship, and I knew very little PHP, so it's quite difficult for me) 我强调我是symfony的初学者(我是在实习的两周前发现它的,而且我对PHP的了解很少,所以对我来说很难)

I do not use the fosUserBundle bundle. 我不使用fosUserBundle捆绑包。

This is my code : 这是我的代码:

User.php : User.php:

<?php

namespace Site\PagesBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Security\Core\User\UserInterface;


/**
 * User
 *
 * @ORM\Table(name="user")
 * @ORM\Entity(repositoryClass="Site\PagesBundle\Repository\UserRepository")
 */
class User implements UserInterface, \Serializable
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

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


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

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



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

     /**
     * @Assert\Length(max=4096)
     */
    private $plainPassword;

    /**
     * @var string
     *
     * @ORM\Column(name="password", type="string", length=64, nullable=true)
     */
    private $password;

    /**
     * @var int
     *
     * @ORM\Column(name="nbTelechargementsAuto", type="integer", nullable=true)
     */
    private $nbTelechargementsAuto;

    /**
     * @var bool
     *
     * @ORM\Column(name="isActif", type="boolean")
     */
    private $isActif=0;

    /**
     * @ORM\Column(type="datetime", nullable=true)
     *
     * @var \DateTime
    */
    private $createdAt;


    /**
     * @var bool
     *
     * @ORM\Column(name="isCreated", type="boolean")
     */
    private $isCreated=0;

    /**
     * @ORM\Column(type="array")
     */
    private $roles;

    /**
     * Set createdAt
     *
     * @param \DateTime $createdAt
     *
     * @return User
     */
    public function setCreatedAt()
    {
        $this->createdAt = new \DateTimeImmutable();

        return $this;
    }

    /**
     * Get createdAt
     *
     * @return \DateTime
     */
    public function getCreatedAt()
    {
        return $this->createdAt;
    }


    /**
     * Get id
     *
     * @return int
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set nom
     *
     * @param string $nom
     *
     * @return User
     */
    public function setNom($nom)
    {
        $this->nom = $nom;

        return $this;
    }

    /**
     * Get nom
     *
     * @return string
     */
    public function getNom()
    {
        return $this->nom;
    }

        /**
     * Set nom
     *
     * @param string $username
     *
     * @return User
     */
    public function setUsername($username)
    {
        $this->username = $username;

        return $this;
    }

    /**
     * Get nom
     *
     * @return string
     */
    public function getUsername()
    {
        return $this->username;
    }

    /**
     * Set prenom
     *
     * @param string $prenom
     *
     * @return User
     */
    public function setPrenom($prenom)
    {
        $this->prenom = $prenom;

        return $this;
    }

    /**
     * Get prenom
     *
     * @return string
     */
    public function getPrenom()
    {
        return $this->prenom;
    }

    /**
     * Set email
     *
     * @param string $email
     *
     * @return User
     */
    public function setEmail($email)
    {
        $this->email = $email;

        return $this;
    }

    /**
     * Get email
     *
     * @return string
     */
    public function getEmail()
    {
        return $this->email;
    }

    /**
     * Set password
     *
     * @param string $password
     *
     * @return User
     */
    public function setPassword($password)
    {
        $this->password = $password;

        return $this;
    }

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

    /**
     * Set nbTelechargementsAuto
     *
     * @param integer $nbTelechargementsAuto
     *
     * @return User
     */
    public function setNbTelechargementsAuto($nbTelechargementsAuto)
    {
        $this->nbTelechargementsAuto = $nbTelechargementsAuto;

        return $this;
    }

    /**
     * Get nbTelechargementsAuto
     *
     * @return int
     */
    public function getNbTelechargementsAuto()
    {
        return $this->nbTelechargementsAuto;
    }

    /**
     * Set isActif
     *
     * @param boolean $isActif
     *
     * @return User
     */
    public function setIsActif($isActif)
    {
        $this->isActif = $isActif;

        return $this;
    }

    /**
     * Get isActif
     *
     * @return bool
     */
    public function getIsActif()
    {
        return $this->isActif;
    }


        /**
     * Set isCreated
     *
     * @param boolean $isCreated
     *
     * @return User
     */
    public function setIsCreated($isCreated)
    {
        $this->isCreated = $isCreated;

        return $this;
    }

    /**
     * Get isCreated
     *
     * @return bool
     */
    public function getIsCreated()
    {
        return $this->isCreated;
    }

    public function __construct()
    {
        $this->roles = ['ROLE_USER'];
    }

    public function getPlainPassword()
    {
        return $this->plainPassword;
    }

    public function setPlainPassword($password)
    {
        $this->plainPassword = $password;
    }

    public function getSalt()
    {
        // you *may* need a real salt depending on your encoder
        // see section on salt below
        return null;
    }

    public function getRoles()
    {
        return $this->roles;
    }

    public function eraseCredentials()
    {
    }

    /** @see \Serializable::serialize() */
    public function serialize()
    {
        return serialize([
            $this->id,
            $this->username,
            $this->password,
            $this->email,
            $this->nbTelechargementsAuto,
            $this->nom,
            $this->prenom,
            // see section on salt below
            // $this->salt,
        ]);
    }

    /** @see \Serializable::unserialize() */
    public function unserialize($serialized)
    {
        list (
            $this->id,
            $this->username,
            $this->password,
            $this->email,
            $this->nbTelechargementsAuto,
            $this->nom,
            $this->prenom,
            // see section on salt below
            // $this->salt
        ) = unserialize($serialized, ['allowed_classes' => false]);
    }


    /**
     * Activation du compte
     */
    public function activerCompte($nbPackages, $nbHomonymes)
    {

        if($this->getIsCreated() == 0)
        {
            $unUsername = $this->getNom();
            $unUsername .= ".";
            $unUsername .= $this->getPrenom();
            $unUsername = strtolower($unUsername);

            if($nbHomonymes > 0)
            {
                $nbHomonymes++;
                $unUsername .= $nbHomonymes;
            }


            $this->setUsername(strtolower($unUsername));
            $this->setNbTelechargementsAuto($nbPackages);
            $this->setCreatedAt();
            $this->setIsCreated(true);

        }

        $password = $this->generatePassword();

        $this->setPlainPassword($password);
        $this->setIsActif(true);

        return $this;
    }

    public function constructionUsername()
    {
        $unUsername = $this->getNom();
        $unUsername .= ".";
        $unUsername .=$this->getPrenom();

        return $unUsername;
    }

    /**
     * Désactivation du compte
     */
    public function desactiverCompte()
    {
        $this->setIsActif(false);
        $this->setCreatedAt();

        return $this;
    }

    public function registration()
    {
        // Passage Nom 1ère lettre Majuscule le reste minuscule
        $leNom = $this->getNom();
        $leNom = strtolower($leNom);
        $leNom = ucfirst($leNom);

        // Passage Nom 1ère lettre Majuscule le reste minuscule
        $lePrenom = $this->getPrenom();
        $lePrenom = strtolower($lePrenom);
        $lePrenom = ucfirst($lePrenom);

        $this->setNom($leNom);
        $this->setPrenom($lePrenom);
        $this->setCreatedAt();
    }

    /**
     * Génération d'un mot de passe
     * $nb_caractere = nombre de caractère du mdp
     * Pas de caractère qui se ressemble (L minuscule, 1 et i majuscule, Zéro et la lettre o.)
     * Sécurité supplémentaire avec : caractères speciaux: - + = $ % ! @ #
     * Pas d'espace pour éviter les erreurs
     */
    function generatePassword($nb_caractere = 7)
{
        $mot_de_passe = "";

        $chaine = "abcdefghjkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ023456789@!$?&";
        $longeur_chaine = strlen($chaine);

        for($i = 1; $i <= $nb_caractere; $i++)
        {
            $place_aleatoire = mt_rand(0,($longeur_chaine-1));
            $mot_de_passe .= $chaine[$place_aleatoire];
        }

        return $mot_de_passe;   
}


}

config.php: config.php:

imports:
    - { resource: parameters.yml }
    - { resource: security.yml }
    - { resource: services.yml }

# Put parameters here that don't need to change on each machine where the app is deployed
# https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
parameters:
    locale: en

framework:
    # ...
    templating:
        engines: ['twig']
    #esi: ~
    #translator: { fallbacks: ['%locale%'] }
    secret: '%secret%'
    router:
        resource: '%kernel.project_dir%/app/config/routing.yml'
        strict_requirements: ~
    form: ~
    csrf_protection: ~
    validation: { enable_annotations: true }
    #serializer: { enable_annotations: true }
    default_locale: '%locale%'
    trusted_hosts: ~
    session:
        # https://symfony.com/doc/current/reference/configuration/framework.html#handler-id
        handler_id: session.handler.native_file
        save_path: '%kernel.project_dir%/var/sessions/%kernel.environment%'
    fragments: ~
    http_method_override: true
    assets: ~
    php_errors:
        log: true

# Twig Configuration
twig:
    debug: '%kernel.debug%'
    strict_variables: '%kernel.debug%'
    form_themes: ['bootstrap_4_layout.html.twig']


# Doctrine Configuration
doctrine:
    dbal:
        driver: pdo_mysql
        host: '%database_host%'
        port: '%database_port%'
        dbname: '%database_name%'
        user: '%database_user%'
        password: '%database_password%'
        charset: UTF8
        # if using pdo_sqlite as your database driver:
        #   1. add the path in parameters.yml
        #     e.g. database_path: '%kernel.project_dir%/var/data/data.sqlite'
        #   2. Uncomment database_path in parameters.yml.dist
        #   3. Uncomment next line:
        #path: '%database_path%'

    orm:
        auto_generate_proxy_classes: '%kernel.debug%'
        naming_strategy: doctrine.orm.naming_strategy.underscore
        auto_mapping: true

# Swiftmailer Configuration
swiftmailer:
    transport: '%mailer_transport%'
    host: '%mailer_host%'
    username: '%mailer_user%'
    password: '%mailer_password%'
    spool: { type: memory }

sensio_framework_extra:
   router:
        annotations: false

assetic:
    debug:          "%kernel.debug%"
    use_controller: false
    bundles:    [ ]
   #java: /usr/bin/java
    java: C:\Program Files\Java\jdk1.8.0_65\bin\java.exe
    filters:
        cssrewrite: ~
        cssembed:
            jar: "%kernel.root_dir%/Resources/java/cssembed.jar"        
            yui_js:
            jar: "%kernel.root_dir%/Resources/java/yuicompressor.jar"
        yui_css:
            jar: "%kernel.root_dir%/Resources/java/yuicompressor.jar"
        lessphp:
            file: "%kernel.root_dir%/../vendor/oyejorge/less.php/lessc.inc.php"   
            apply_to: ".less$"
    assets:
        jquery_js:
            inputs:
                - "%kernel.root_dir%/../vendor/components/jquery/jquery.min.js"            
            filters: [?yui_js]
            output: js/jquery.min.js

        bootstrap_css:
            inputs:
                - "%kernel.root_dir%/../vendor/twbs/bootstrap/less/bootstrap.less"
            filters:
                - lessphp
                - cssrewrite
            output: css/bootstrap.css            

        bootstrap_js:
            inputs:
                - "%kernel.root_dir%/../vendor/twbs/bootstrap/js/affix.js"
                - "%kernel.root_dir%/../vendor/twbs/bootstrap/js/alert.js"
                - "%kernel.root_dir%/../vendor/twbs/bootstrap/js/button.js"
                - "%kernel.root_dir%/../vendor/twbs/bootstrap/js/carousel.js"
                - "%kernel.root_dir%/../vendor/twbs/bootstrap/js/collapse.js"
                - "%kernel.root_dir%/../vendor/twbs/bootstrap/js/dropdown.js"
                - "%kernel.root_dir%/../vendor/twbs/bootstrap/js/modal.js"
                - "%kernel.root_dir%/../vendor/twbs/bootstrap/js/tooltip.js"
                - "%kernel.root_dir%/../vendor/twbs/bootstrap/js/popover.js"
                - "%kernel.root_dir%/../vendor/twbs/bootstrap/js/scrollspy.js"
                - "%kernel.root_dir%/../vendor/twbs/bootstrap/js/tab.js"
                - "%kernel.root_dir%/../vendor/twbs/bootstrap/js/transition.js"
            filters: [?yui_js]
            output: js/bootstrap.js             
        fonts_glyphicons_eot:
            inputs:
                - "%kernel.root_dir%/../vendor/twbs/bootstrap/fonts/glyphicons-halflings-regular.eot"
            output: "fonts/glyphicons-halflings-regular.eot"
        fonts_glyphicons_svg:
            inputs:
                - "%kernel.root_dir%/../vendor/twbs/bootstrap/fonts/glyphicons-halflings-regular.svg"
            output: "fonts/glyphicons-halflings-regular.svg"
        fonts_glyphicons_ttf:
            inputs:
                - "%kernel.root_dir%/../vendor/twbs/bootstrap/fonts/glyphicons-halflings-regular.ttf"
            output: "fonts/glyphicons-halflings-regular.ttf"
        fonts_glyphicons_woff:
            inputs:
                - "%kernel.root_dir%/../vendor/twbs/bootstrap/fonts/glyphicons-halflings-regular.woff"

            output: "fonts/glyphicons-halflings-regular.woff"

stof_doctrine_extensions: 
    orm: 
        default: 
            sluggable: true

vich_uploader:
    db_driver: orm
    twig: true
    storage: file_system

    mappings:
        paquet:
            uri_prefix: fichiers/packages
            upload_destination: '%kernel.root_dir%/../web/fichiers/packages/' 

            inject_on_load: true
            delete_on_update: true
            delete_on_remove: true

        notice:
            uri_prefix: fichiers/notices
            upload_destination: '%kernel.root_dir%/../web/fichiers/notices/' 

            inject_on_load: false
            delete_on_update: true
            delete_on_remove: true

fos_ck_editor:
    configs:
        my_config:
            toolbar: [ ["Source", "-", "Save"], "/", ["Anchor"], "/", ["Maximize"] ]
            uiColor:                "#000000"

Security.yml : Security.yml:

# To get started with security, check out the documentation:
# https://symfony.com/doc/current/security.html
security:
    encoders:
        Site\PagesBundle\Entity\User: bcrypt

    role_hierarchy:
        ROLE_ADMIN:       ROLE_USER
        ROLE_SUPER_ADMIN: [ ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH ]

    # https://symfony.com/doc/current/security.html#b-configuring-how-users-are-loaded
    providers:
        in_memory: {memory: ~}
        in_database:
            entity:
                class: Site\PagesBundle\Entity\User
                property: username

        our_db_provider:
            entity:
                class: Site\PagesBundle\Entity\User
                property: username
                # if you're using multiple entity managers
                # manager_name: customer

    firewalls:
        # disables authentication for assets and the profiler, adapt it according to your needs
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false

        main:
            anonymous: true

            provider: in_database

            form_login:
                login_path: security_login
                check_path: security_login

            logout:
                path: security_logout
                target: informations

            # activate different ways to authenticate

            # https://symfony.com/doc/current/security.html#a-configuring-how-your-users-will-authenticate
            #http_basic: ~

            # https://symfony.com/doc/current/security/form_login_setup.html
            #form_login: ~

And a part fo the controller that I use to manage what is relative to the navigation of the user, including its authentication 控制器的一部分,我用来管理与用户导航相关的内容,包括其身份验证

DefaultController.php : DefaultController.php:

<?php

namespace Site\PagesBundle\Controller;

use Site\PagesBundle\Entity\User;
use Site\PagesBundle\Entity\Paquet;
use Site\PagesBundle\Entity\TypeUser;
use Site\PagesBundle\Entity\Information;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Vich\UploaderBundle\Handler\DownloadHandler;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;

/**
 * Default controller.
 *
 * @Route("accueil")
 */
class DefaultController extends Controller
{

    /**
     * Accueil
     *
     * @Route("/", name="connexion_index")
     * @Method({"GET", "POST"})
     */
    public function indexAction(Request $request, UserPasswordEncoderInterface $passwordEncoder)
    {

        $em = $this->getDoctrine()->getManager(); //Récupération du manager

        $listeInfos = $em->getRepository('PagesBundle:Information')->getInformationsZone("Zone 1"); //Récupération d'une liste d'informations

        $user = new User(); //Initialisation de l'objet User
        $form = $this->createForm('Site\PagesBundle\Form\ConnexionType', $user); //Formulaire de création
        $form->handleRequest($request);

        //Traitement si le formulaire est soumis ( Ajout du package dans la BDD )
        if ($form->isSubmitted() && $form->isValid()) {
            $em = $this->getDoctrine()->getManager();
            $em->persist($user);

            $password = $passwordEncoder->encodePassword($user, $user->getPlainPassword());

            $valide = $this->getDoctrine()->getManager()->getRepository('PagesBundle:User')->authentifier($user->getUsername(),$password);
            dump($valide);
            dump($password);

            if($valide == 1)
            {
                return $this->redirectToRoute('accueil');
            }

            else
            {
                return $this->render('@Pages/Default/connexion.html.twig',array(
                    'user' => $user,
                    'form' => $form->createView(),
                    'listeInfos' => $listeInfos,
                ));
            }

            // On ajoute un package, donc on offre un téléchargement supplémentaire aux utilisateurs concernés
            $this->getDoctrine()->getManager()->getRepository('PagesBundle:User')->updateNbDDLAll("inc"); 

            //return $this->redirectToRoute('paquets_index'); // Redirection page de gestion de packages
        }



        return $this->render('@Pages/Default/connexion.html.twig',array(
            'user' => $user,
            'form' => $form->createView(),
            'listeInfos' => $listeInfos,
        ));
    }

Thanks for your help ! 谢谢你的帮助 !

EDIT: 编辑:

My function : 我的职能:

 /**
     * Accueil
     *
     * @Route("/", name="connexion_index")
     * @Method({"GET", "POST"})
     */
    public function indexAction(Request $request, UserPasswordEncoderInterface $passwordEncoder)
    {

        $em = $this->getDoctrine()->getManager(); //Récupération du manager

        $listeInfos = $em->getRepository('PagesBundle:Information')->getInformationsZone("Zone 1"); //Récupération d'une liste d'informations

        $user = new User(); //Initialisation de l'objet User
        $form = $this->createForm('Site\PagesBundle\Form\ConnexionType', $user); //Formulaire de création
        $form->handleRequest($request);

        //Traitement si le formulaire est soumis ( Ajout du package dans la BDD )
        if ($form->isSubmitted() && $form->isValid()) {
            $em = $this->getDoctrine()->getManager();
            $em->persist($user);

            $password = $passwordEncoder->encodePassword($user, $user->getPlainPassword());

            $valide = $this->getDoctrine()->getManager()->getRepository('PagesBundle:User')->authentifier($user->getUsername(),$password);
            dump($valide);
            dump($password);

            if($valide == 1)
            {
                return $this->redirectToRoute('accueil');
            }

            else
            {
                return $this->render('@Pages/Default/connexion.html.twig',array(
                    'user' => $user,
                    'form' => $form->createView(),
                    'listeInfos' => $listeInfos,
                ));
            }

            // On ajoute un package, donc on offre un téléchargement supplémentaire aux utilisateurs concernés
            $this->getDoctrine()->getManager()->getRepository('PagesBundle:User')->updateNbDDLAll("inc"); 

            //return $this->redirectToRoute('paquets_index'); // Redirection page de gestion de packages
        }

I retrieve the password entered by the user in the login form. 我检索用户在登录表单中输入的密码。 I encrypt it. 我加密它。 Then I run a check in my UserRepository with the username and password encrypted. 然后,我在UserRepository中运行了一个用户名和密码已加密的检查。 If the function returns true, there is someone who has the username entered and the encrypted password entered. 如果该函数返回true,则表明有人输入了用户名并输入了加密密码。

My UserRepository function : 我的UserRepository函数:

public function authentifier($username, $password)
    {
        $queryBuilder = $this->createQueryBuilder("u")
        ->select("count(u.id)")
        ->where("u.username = :username")
        ->andWhere("u.password = :password")
        ->setParameter("username",$username)
        ->setParameter("password",$password);
        return $queryBuilder->getQuery()->getSingleScalarResult();
    }
}

However, what is the cost in the security.yml? 但是,security.yml的成本是多少?

To check if the posted password on your login form match with the one in database, you just need to bcrypt it and check if it's the same as the one in db. 要检查登录表单上发布的密码是否与数据库中的密码匹配,您只需对其进行加密并检查其是否与db中的密码相同。

  • You get your User from db 您从数据库获取User
  • you encode the posted password 您对发布的密码进行编码
  • You check if the posted encoded password is the same as the one sotred in your User 您检查发布的编码密码是否与您的User密码相同

But in your Controller code, it seems you create a new user (you create a new User instrad of getting one from db, and you persist it) ? 但是在您的Controller代码中,似乎您创建了一个新用户(您创建了一个从db获取一个新的User instrad并将其持久化)?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM