Symfony 2.3 Bad Credentials 自定义提供程序

Posted

技术标签:

【中文标题】Symfony 2.3 Bad Credentials 自定义提供程序【英文标题】:Symfony 2.3 Bad Credentials Custom provider 【发布时间】:2013-10-23 04:49:04 【问题描述】:

此刻我完全迷失了,两天后我试图弄清楚为什么我总是在我的登录表单上获得“错误凭据”响应。

我用过How to load Security Users from the Database 教程。

有什么方法可以知道他在比较什么来得到那个“坏凭据”错误?

转储错误:

exception 'Symfony\Component\Security\Core\Exception\BadCredentialsException' with message 'Bad credentials' in D:\dev\workspace\esig_grandprojet\vendor\symfony\symfony\src\Symfony\Component\Security\Core\Authentication\Provider\UserAuthenticationProvider.php:89 Stack trace: 
#0 D:\dev\workspace\esig_grandprojet\app\cache\dev\classes.php(107): session_start() 
#1 D:\dev\workspace\esig_grandprojet\app\cache\dev\classes.php(184): Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage->start() 
#2 D:\dev\workspace\esig_grandprojet\app\cache\dev\classes.php(482): Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage->getBag('attributes') 
#3 D:\dev\workspace\esig_grandprojet\src\ESIG\BBC\ManagerCP2Bundle\Controller\SecurityController.php(45): Symfony\Component\HttpFoundation\Session\Session->get('_security.last_...') 
#4 [internal function]: ESIG\BBC\ManagerCP2Bundle\Controller\SecurityController->loginAction() 
#5 D:\dev\workspace\esig_grandprojet\app\bootstrap.php.cache(2844): call_user_func_array(Array, Array) 
#6 D:\dev\workspace\esig_grandprojet\app\bootstrap.php.cache(2818): Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object(Symfony\Component\HttpFoundation\Request), 1) 
#7 D:\dev\workspace\esig_grandprojet\app\bootstrap.php.cache(2947): Symfony\Component\HttpKernel\HttpKernel->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true) 
#8 D:\dev\workspace\esig_grandprojet\app\bootstrap.php.cache(2249): Symfony\Component\HttpKernel\DependencyInjection\ContainerAwareHttpKernel->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true) 
#9 D:\dev\workspace\esig_grandprojet\web\app_dev.php(28): Symfony\Component\HttpKernel\Kernel->handle(Object(Symfony\Component\HttpFoundation\Request)) 
#10 main

这是我的文件:

我的 security.yml :

security:
    encoders:
        ESIG\BBC\ManagerCP2Bundle\Entity\Utilisateur:
            algorithm: sha512
            encode_as_base64: true
            iterations: 5000

    providers:
        users:
            entity:  class: ESIGBBCManagerCP2Bundle:Utilisateur 

    firewalls:
        dev:
            pattern:  ^/(_(profiler|wdt)|css|images|js)/
            security: false

        login:
            pattern:  ^/login$
            security: false

        main:
            pattern:    /.*
            form_login:
                # The user is redirected here when he needs to login
                login_path: _security_login
                #if true, forward the user to the login form instead of redirecting
                use_forward: false
                # submit the login form here
                check_path: _security_check
                # by default, the login form *must* be a POST, not a GET
                post_only: true
                # login success redirecting options
                always_use_default_target_path: true
                default_target_path:            /
                target_path_parameter:          _target_path
                use_referer:                    false
                # login failure redirecting options
                failure_path:                     null
                failure_forward:                  false

                # field names for the username and password fields
                username_parameter:               _username
                password_parameter:               _password

                #csrf token options
                csrf_parameter:                   _csrf_token
                intention:                        authenticate

            logout: true
            security: true
            anonymous: true

            remember_me:
                key:       "%secret%"
                lifetime: 3600
                path:      /
                domain: ~ #Default to the current domain from $_SERVER

    access_control:
        -  path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY         
        -  path: /.*, roles: IS_AUTHENTICATED_REMEMBERED 
        #-  path: ^/demo/secured/hello/admin/, roles: ROLE_ADMIN 
        #-  path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY, requires_channel: https 

我的用户实体:

<?php

namespace ESIG\BBC\ManagerCP2Bundle\Entity;

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

/**
 * Utilisateur
 *
 * @ORM\Table(name="mcp2_utilisateur")
 * @ORM\Entity(repositoryClass="ESIG\BBC\ManagerCP2Bundle\Entity\UtilisateurRepository")
 * @ORM\InheritanceType("SINGLE_TABLE")
 * @ORM\DiscriminatorColumn(name="uti_discr", type="string")
 * @ORM\DiscriminatorMap("utilisateur" = "Utilisateur", "pompier" = "Pompier")
 * 
 * @UniqueEntity(fields="username", message="error.input.unique.user")
 * @UniqueEntity(fields="email", message="error.input.unique.mail")
 */

class Utilisateur implements AdvancedUserInterface, \Serializable

    /**
     * @var integer
     *
     * @ORM\Column(name="uti_id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="uti_nom_utilisateur", type="string", length=50, unique=true)
     * @Assert\NotBlank(message="error.input.blank")
     */
    private $username;

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

    /**
     * @var string
     *
     * @ORM\Column(name="uti_mot_de_passe", type="string", length=255)
     * @Assert\NotBlank(message="error.input.blank")
     */
    private $password;

    /**
     * @var string
     *
     * @ORM\Column(name="uti_email", type="string", length=100, unique=true)
     * @Assert\NotBlank(message="error.input.blank")
     * @Assert\Email(message="error.input.invalid.mail")
     */
    private $email;

    /**
     * @var boolean
     *
     * @ORM\Column(name="uti_is_active", type="boolean")
     * @Assert\NotBlank(message="error.input.blank")
     */
    private $isActive;    

    /**
     * @var boolean
     *
     * @ORM\Column(name="uti_mot_de_passe_expire", type="boolean")
     * @Assert\NotBlank(message="error.input.blank")
     */
    private $motDePasseExpire;


    /**
     * @var string
     *
     * @ORM\Column(name="uti_nom", type="string", length=50)
     * @Assert\NotBlank(message="error.input.blank")
     */
    private $nom;

    /**
     * @var string
     *
     * @ORM\Column(name="uti_prenom", type="string", length=50)
     * @Assert\NotBlank(message="error.input.blank")
     */
    private $prenom;

    /**
     * @var string
     *
     * @ORM\Column(name="uti_adresse", type="text")
     * @Assert\NotBlank(message="error.input.blank")
     */
    private $adresse;

    /**
     * @var string
     *
     * @ORM\Column(name="uti_telephone", type="string", length=13)
     * @Assert\NotBlank(message="error.input.blank")
     */
    private $telephone;

    /**
     * @var boolean
     *
     * @ORM\Column(name="uti_date_derniere_connexion", type="boolean", nullable=true)
     */
    private $dateDerniereConnexion;    

    /**
     * @var ArrayCollection
     * 
     * @ORM\ManyToMany(targetEntity="GroupeAutorisation", inversedBy="utilisateurs")
     * @ORM\JoinTable(name="mcp2_associe",
     *      joinColumns=@ORM\JoinColumn(name="ass_uti_id", referencedColumnName="uti_id"),
     *      inverseJoinColumns=@ORM\JoinColumn(name="ass_gra_id", referencedColumnName="gra_id")
     *      )
     */
    private $groupesAutorisation;

    /**
     * @var ArrayCollection
     * 
     * @ORM\OneToMany(targetEntity="Notification", mappedBy="utilisateur", cascade="persist", "remove")
     */
    private $notifications;

    public function __construct() 
        $this->isActive = True;
        $this->salt = md5(uniqid(null, true));

        $this->groupesAutorisation = new \Doctrine\Common\Collections\ArrayCollection();
        $this->notifications = new \Doctrine\Common\Collections\ArrayCollection();
        $this->motDePasseExpire = False;

    

    /**
     * Returns the username used to authenticate the user.
     *
     * @return string The username
     */
    public function getUsername() 
        return $this->username;
    


    public function getSalt() 
        //return $this->salt;
        return null;

    


    public function getPassword() 
        $this->password;
    


    public function getRoles() 
        // special
        //return $this->groupesAutorisation->toArray();
        return array('ROLE_USER');
    


    public function equals(UserInterface $user)
    
            /* 
            if (!$account instanceof Account) 
                    return false;
            

            if($this->password !== $user->getPassword()) 
                    return false;
            

            if($this->getSalt() !== $user->getSalt()) 
                    return false;
            

            if($this->getUsername() !== $user->getUsername()) 
                    return false;
            

            return true; */

            return md5($this->getUsername()) == md5($user->getUsername());
    

    /**
     * Removes sensitive data from the user.
     *
     * This is important if, at any given point, sensitive information like
     * the plain-text password is stored on this object.
     */
    public function eraseCredentials() 

    

    /**
     * @see \Serializable::serialize()
     */
    public function serialize()
    
        return serialize(array(
            $this->id,
        ));
    

    /**
     * @see \Serializable::unserialize()
     */
    public function unserialize($serialized)
    
        list (
            $this->id,
        ) = unserialize($serialized);
    

    public function isAccountNonExpired()
    
        return true;
    

    public function isAccountNonLocked()
    
        return true;
    

    public function isCredentialsNonExpired()
    
        return true;
    

    public function isEnabled()
    
        return $this->isActive;
        

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

    /**
     * Set username 
     *
     * @param string $username 
     * @return Utilisateur
     */
    public function setUsername($nomUtilisateur)
    
        $this->username = $nomUtilisateur;

        return $this;
    

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

        return $this;
    


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

        return $this;
    

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


    /**
     * Get groupes
     *
     * @return \Doctrine\Common\Collections\Collection 
     */
    public function getGroupes()
    
        return $this->groupes;
    

    /**
     * Add notifications
     *
     * @param \ESIG\BBC\ManagerCP2Bundle\Entity\Notification $notifications
     * @return Utilisateur
     */
    public function addNotification(\ESIG\BBC\ManagerCP2Bundle\Entity\Notification $notifications)
    
        $this->notifications[] = $notifications;

        return $this;
    


    /**
     * Add groupesAutorisation
     *
     * @param \ESIG\BBC\ManagerCP2Bundle\Entity\GroupeAutorisation $groupesAutorisation
     * @return Utilisateur
     */
    public function addGroupesAutorisation(\ESIG\BBC\ManagerCP2Bundle\Entity\GroupeAutorisation $groupesAutorisation)
    
        $this->groupesAutorisation[] = $groupesAutorisation;

        return $this;
    

    /**
     * Remove groupesAutorisation
     *
     * @param \ESIG\BBC\ManagerCP2Bundle\Entity\GroupeAutorisation $groupesAutorisation
     */
    public function removeGroupesAutorisation(\ESIG\BBC\ManagerCP2Bundle\Entity\GroupeAutorisation $groupesAutorisation)
    
        $this->groupesAutorisation->removeElement($groupesAutorisation);
    

    /**
     * Get groupesAutorisation
     *
     * @return \Doctrine\Common\Collections\Collection 
     */
    public function getGroupesAutorisation()
    
        return $this->groupesAutorisation;
    

    /**
     * Set salt
     *
     * @param string $salt
     * @return Utilisateur
     */
    public function setSalt($salt)
    
        $this->salt = $salt;

        return $this;
    

    /**
     * Set isActive
     *
     * @param boolean $isActive
     * @return Utilisateur
     */
    public function setIsActive($isActive)
    
        $this->isActive = $isActive;

        return $this;
    

    /**
     * Get isActive
     *
     * @return boolean 
     */
    public function isActive()
    
        return $this->isActive;
    

(getSalt 返回“null”只是为了确保他没有参与我的问题)

我的用户存储库:

<?php
namespace ESIG\BBC\ManagerCP2Bundle\Entity;

use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\NoResultException;
use ESIG\BBC\ManagerCP2Bundle\Entity\Notification;

/**
 * UtilisateurRepository
 *
 * This class was generated by the Doctrine ORM. Add your own custom
 * repository methods below.
 */
class UtilisateurRepository extends EntityRepository implements UserProviderInterface



    public function loadUserByUsername($username)
    
        $q = $this
            ->createQueryBuilder('u')
            ->where('u.username = :username OR u.email = :email')
            ->setParameter('username', $username)
            ->setParameter('email', $username)
            ->getQuery();

        try 
            // La méthode Query::getSingleResult() lance une exception
            // s'il n'y a pas d'entrée correspondante aux critères
            $user = $q->getSingleResult();
         catch (NoResultException $e) 
            throw new UsernameNotFoundException(sprintf('Unable to find an active admin AcmeUserBundle:User object identified by "%s".', $username), 0, $e);
        

        return $user;
    

    public function refreshUser(UserInterface $user)
    
        $class = get_class($user);
        if (!$this->supportsClass($class)) 
            throw new UnsupportedUserException(
                sprintf(
                    'Instances of "%s" are not supported.',
                    $class
                )
            );
        

        return $this->find($user->getId());

    

    public function supportsClass($class)
    
        return $this->getEntityName() === $class || is_subclass_of($class, $this->getEntityName());
    

我的安全控制器:

<?php

namespace ESIG\BBC\ManagerCP2Bundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Component\Security\Core\SecurityContext;

class SecurityController extends Controller

    /**
     * @Template("ESIGBBCManagerCP2Bundle::menu.html.twig")
     */
    public function GenerateMenuAction()
    
        return array();
    

    /**
     * @Route("/login", name="_security_login")
     * @Template("ESIGBBCManagerCP2Bundle:Security:login.html.twig")
     */
    public function loginAction()
    


        $request = $this->getRequest();
        $session = $request->getSession();

        // Récupère l'erreur de login si il y en a une
        if ($request->attributes->has(SecurityContext::AUTHENTICATION_ERROR)) 
            $error = $session->attributes->get(SecurityContext::AUTHENTICATION_ERROR);
         else 
            $error = $session->get(SecurityContext::AUTHENTICATION_ERROR);
            $session->remove(SecurityContext::AUTHENTICATION_ERROR);
        

        return array(
            'last_username' => $session->get(SecurityContext::LAST_USERNAME),
            'error'         => $error
        );
    
     /**
     * @Route("/login_check", name="_security_check")
     * @Template("ESIGBBCManagerCP2Bundle:Security:login.html.twig")
     */   
    public function securityCheckAction()
    


    
    /**
     * @Route("/logout", name="_security_logout")
     * @Template("ESIGBBCManagerCP2Bundle:Security:login.html.twig")
     */
    public function logoutAction()
    
        return array();
        



我的登录表单模板:

% extends "ESIGBBCManagerCP2Bundle::ManagerCP2.html.twig" %
% block right %
 error 
    % if error %
        <div> error.message </div>
    % endif %
         test 
    <form action=" path('_security_check') " method="post">


        <label for="username">Login :</label>
        <input type="text" id="username" name="_username" value=" last_username " title=" "login.mail.title" | trans " /><br />

        <label for="password" >Mot de passe :</label>
        <input type="password" id="password" name="_password" title=" "login.password.title" | trans " /><br />
        <input type="checkbox" id="remember_me" name="_remember_me" title=" "login.rememberme.title" | trans " checked />        <label for="remember_me" >Se souvenir de moi</label><br />

        #
            Si vous voulez contrôler l'URL vers laquelle l'utilisateur est redirigé en cas de succès
            (plus de détails ci-dessous)
            <input type="hidden" name="_target_path" value="/account" />
        #

        <button type="submit" name="login" title=" "login.submit.title" | trans "> "login.submit.value" | trans </button>
    </form>
% endblock %

最后:我的固定装置

<?php

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
namespace ESIG\BBC\ManagerCP2Bundle\DataFixtures\ORM;

use Doctrine\Common\DataFixtures\FixtureInterface;
use Doctrine\Common\Persistence\ObjectManager;
use ESIG\BBC\ManagerCP2Bundle\Entity\Pompier;
use ESIG\BBC\ManagerCP2Bundle\Entity\Utilisateur;
use \Symfony\Component\Security\Core\Encoder\Pbkdf2PasswordEncoder;
use Symfony\Component\Security\Core\Encoder\MessageDigestPasswordEncoder;
/**
 * Description of LoadUserData
 *
 * @author noirv_000
 */
class LoadUserData implements FixtureInterface


    public function load(ObjectManager $manager)
                  

       $pwd_encoder = new MessageDigestPasswordEncoder('sha512', true, 5000);


        // Super Administrateur
        $superAdmin = new Utilisateur();
        $superAdmin->setNom("Admin")
                    ->setPrenom("Super")
                    ->setUsername("super.admin")
                    ->setEmail("super@admin.foo")
                    ->setPassword($pwd_encoder->encodePassword("12345678", $superAdmin->getSalt()))
                    ->setAdresse("Chemin de l'administration")
                    ->setTelephone("0041000000000");
        $manager->persist($superAdmin);


        // Enregistre toutes les nouvelles entrées
        $manager->flush();
    


请救救我T_T

【问题讨论】:

【参考方案1】:

首先检查 UserAuthenticationProvider 如何对您的密码进行编码,并将其与 datafixtures 生成的密码进行比较

【讨论】:

【参考方案2】:

试试这个:

$pwd_encoder = new EncoderFactory(array('Symfony\Component\Security\Core\User\UserInterface' => new MessageDigestPasswordEncoder('sha1',true,500)));

 // Super Administrateur
    $superAdmin = new Utilisateur();
    $superAdmin->setNom("Admin")
                ->setPrenom("Super")
                ->setUsername("super.admin")
                ->setEmail("super@admin.foo")
                ->setPassword($pwd_encoder->getEncoder($superAdmin)->encodePassword("12345678", $superAdmin->getSalt()))
                ->setAdresse("Chemin de l'administration")
                ->setTelephone("0041000000000");

【讨论】:

以上是关于Symfony 2.3 Bad Credentials 自定义提供程序的主要内容,如果未能解决你的问题,请参考以下文章

Nginx 用 502 Bad Gateway 覆盖一般的 symfony 错误

Ngrok 到 dockerised symfony 5 的隧道以 502 bad gateway 结束

Symfony4 + jwt-auth rescipe 总是返回 "code":401,"message":"Bad credentials"

Symfony 2.3/2.4 独立表单组件

Symfony 2.3 使用 handleRequest 验证表单非常慢

symfony 2.3 在 __construct 函数中调用非对象的成员函数 get()