2013-11-20 51 views
1

我已經實現了一個簡單的密碼更改算法。下面的代碼:學說 - preUpdate事件訂閱者根本不被解僱

public function postChangePasswordAction(Request $request, $username) 
    { 
     $em = $this->getDoctrine()->getManager(); 
     $user = $em->getRepository("TskUserBundle:User")->findOneByUsername($username); 
     if(!$user) 
     { 
      throw $this->createNotFoundException("User not found!"); 
     } 
     $form = $this->createPasswordChangeForm(); 
     $form->handleRequest($request); 
     $old_password = $form->get('old_password')->getData(); 
     $new_password = $form->get("new_password")->getData(); 
     if($form->isValid()) 
     { 
      $old_password_encoded = $this->get("tsk_encoder")->encode($user, $old_password, $user->getSalt()); 
      if($old_password_encoded == $user->getPassword()) 
      { 
       $user->setPlainPassword($new_password); 
       $user->setFirstname("rofa"); 
       $em->flush(); 
       return $this->redirect($this->generateUrl("tsk_user_profile", array("username"=>$user->getUsername()))); 
      } else { return new Response($old_password_encoded."\n".$user->getPassword());} 
     } 

     return $this->render("TskUserBundle:User:change_password.html.twig", array("username" => $user->getUsername(), "form"=>$form->createView())); 
    } 

User實體是:

<?php 

namespace Tsk\UserBundle\Entity; 

use Symfony\Component\Security\Core\User\AdvancedUserInterface; 
use Doctrine\ORM\Mapping as ORM; 
use Doctrine\Common\Collections\ArrayCollection; 
use Symfony\Component\Validator\Constraints as Assert; 

/** 
* @ORM\Entity(repositoryClass="Tsk\UserBundle\Repository\UserRepository") 
* @ORM\Table(name="users") 
* @ORM\HasLifecycleCallbacks 
* @Assert\GroupSequence({"FormCreate", "FormEdit", "User"}) 
*/ 
class User implements AdvancedUserInterface, \Serializable 
{ 
    /** 
    * @ORM\Column(type="integer") 
    * @ORM\Id 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    protected $id; 

    /** 
    * @ORM\Column(type="string", length=25, unique=true) 
    * @Assert\NotBlank(groups={"FormEdit", "FormCreate"}) 
    */ 
    protected $username; 

    /** 
    * @Assert\NotBlank(groups={"FormCreate"}) 
    * @Assert\Length(min="4", minMessage="Password must be 4 characters at least", groups={"FormCreate"}) 
    */ 
    protected $plain_password; 

    /** 
    * @ORM\Column(type="string", length=128) 
    * @Assert\NotBlank 
    */ 
    protected $password; 

    /** 
    * @ORM\Column(type="string", length=50, unique=true) 
    * @Assert\Email(groups={"FormEdit", "FormCreate"}); 
    */ 
    protected $email; 

    /** 
    * @ORM\Column(type="boolean") 
    */ 
    protected $is_active; 

    /** 
    * @ORM\Column(type="string", length=59) 
    * @Assert\NotBlank(groups={"FormEdit", "FormCreate"}) 
    */ 
    protected $firstname; 

    /** 
    * @ORM\Column(type="string", length=59) 
    * @Assert\NotBlank(groups={"FormEdit", "FormCreate"}) 
    */ 
    protected $lastname; 

    /** 
    * @ORM\ManyToMany(targetEntity="Role", inversedBy="users", cascade={"persist"}) 
    * @Assert\NotBlank 
    */ 
    protected $roles; 

    /** 
    * @ORM\Column(type="string", length=50) 
    */ 
    protected $salt; 

    public function __construct() 
    { 
     $this->roles = new ArrayCollection(); 
     $this->salt = md5(uniqid(null, true)); 
    } 

    /** 
    * @ORM\PrePersist 
    */ 
    public function setIsActiveValue() 
    { 
     $this->setIsActive(true); 
    } 

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

    public function setPlainPassword($plain_password) 
    { 
     $this->plain_password = $plain_password; 
     return $this; 
    } 

    public function setPassword($password) 
    { 
     $this->password = $password; 
     return $this; 
    } 

    public function isAccountNonExpired() 
    { 
     return true; 
    } 

    public function isAccountNonLocked() 
    { 
     return true; 
    } 

    public function isCredentialsNonExpired() 
    { 
     return true; 
    } 

    public function isEnabled() 
    { 
     return $this->getIsActive(); 
    } 

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

    public function getPassword() 
    { 
     return $this->password; 
    } 

    public function getSalt() 
    { 
     return $this->salt; 
    } 

    public function getUsername() 
    { 
     return $this->username; 
    } 

    /** 
    * 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() 
    { 

    } 

    public function serialize() 
    { 
     return serialize(array($this->getUsername())); 
    } 


    public function unserialize($serialized) 
    { 
     list($this->username) = unserialize($serialized); 
    } 


    public function getId() 
    { 
     return $this->id; 
    } 

    public function setUsername($username) 
    { 
     $this->username = $username; 

     return $this; 
    } 

    public function setEmail($email) 
    { 
     $this->email = $email; 

     return $this; 
    } 

    public function getEmail() 
    { 
     return $this->email; 
    } 

    public function setIsActive($isActive) 
    { 
     $this->is_active = $isActive; 

     return $this; 
    } 

    public function getIsActive() 
    { 
     return $this->is_active; 
    } 

    public function setFirstname($firstname) 
    { 
     $this->firstname = $firstname; 

     return $this; 
    } 

    public function getFirstname() 
    { 
     return $this->firstname; 
    } 

    public function setLastname($lastname) 
    { 
     $this->lastname = $lastname; 

     return $this; 
    } 

    public function getLastname() 
    { 
     return $this->lastname; 
    } 

    public function addRole(Role $roles) 
    { 
     $this->roles[] = $roles; 

     return $this; 
    } 

    public function removeRole(Role $roles) 
    { 
     $this->roles->removeElement($roles); 
    } 

} 

我有兩個prePersistpreUpdate事件訂戶。當我創建一個新用戶時,它通常會被解僱。但是,當我只更改密碼它根本不起作用。 (注意plain_password屬性是一個虛擬的沒有得到保存在數據庫中。)

下面的代碼:

<?php 
namespace Tsk\UserBundle\EventSubscriber; 

use Doctrine\Common\EventSubscriber; 
use Doctrine\ORM\Event\LifecycleEventArgs; 
use Tsk\UserBundle\Entity\User; 
use Tsk\UserBundle\Utils\Encoder; 

class EncoderSubscriber implements EventSubscriber 
{ 
    protected $encoder; 

    public function __construct(Encoder $ef) 
    { 
     $this->encoder = $ef; 
    } 

    /** 
    * Returns an array of events this subscriber wants to listen to. 
    */ 
    public function getSubscribedEvents() 
    { 
     return array(
      'preUpdate', 
      'prePersist', 
     ); 
    } 

    public function preUpdate(LifecycleEventArgs $args) 
    { 
     $this->encode($args); 
    } 

    public function prePersist(LifecycleEventArgs $args) 
    { 
     $this->encode($args); 
    } 

    protected function encode(LifecycleEventArgs $args) 
    { 
     $user = $args->getEntity(); 

     if($user instanceof User) 
     { 
      $encodedPassword = ($this->encoder->encode($user, $user->getPlainPassword(), $user->getSalt())); 
      $user->setPassword($encodedPassword); 
     } 
    } 
} 
?> 
+0

在您的postChangePasswordAction上,您需要在調用刷新之前保留您的$ user對象。 –

+0

@joaoalves我試過了。不幸的是,它不能解決問題。 –

+0

你確定postChangePasswordAction在密碼更改時被調用嗎? – George

回答

4

我遇到同樣的問題了。

原因是,Doctrine的工作單元無法計算原始實體和密碼更改實體之間的更改集,因爲plain_password不會保留到數據庫中,因此plain_password字段中的更改是工作單位忽略(或者我應該說,工作單位在調用flush之前和調用flush之前發現數據沒有區別)。

使其工作的方法是在致電EntityManager#flush之前更新password。我通過在檢測到密碼更改(當然是手動)時調度我的UserEvents::CHANGE_PASSWORD來實現此目的。通過使用此方法,您不必再訂閱preUpdate活動,只要您要更新其中的密碼字段即可。

您也可以參考FOSUserBundle的實現。