2017-06-08 24 views
13

repository with issueSymfony 3, wypełnianie żeton i orzeźwiający użytkownik

Mam formularz dla podmiotów użytkownik z dziedziny e-mail:

->add('email', EmailType::class, [ 
       'constraints' => [ 
        new NotBlank(), 
        new Email([ 
         'checkMX' => true, 
        ]) 
       ], 
       'required' => true 
      ]) 

kiedy jestem edycji e-mail do czegoś jak [email protected] i złożyć formularz pokazuje mnie error "Ta wartość nie jest prawidłowym adresem e-mail." to jest OK, ale po tym symfony zapełnić zły e-mail do tokena, a kiedy idę do jakiejkolwiek innej strony lub po prostu przeładować stronę, ja dostaję to:

UWAGA bezpieczeństwa Nazwa użytkownika nie została znaleziona w wybranym użytkownik dostawca.

Myślę, że pytanie brzmi: dlaczego symfony zapełniają błędnie E-mail, który nie przeszedł sprawdzenia poprawności na token i jak mógłbym mu zapobiec?

kontroler:

public function meSettingsAction(Request $request) 
    { 

     $user = $this->getUser(); 
     $userUnSubscribed = $this->getDoctrine()->getRepository('AppBundle:UserUnsubs')->findOneBy(
      [ 
       'email' => $user->getEmail(), 
      ] 
     ); 

     $form = $this->createForm(UserSettingsType::class, $user); 
     $form->get('subscribed')->setData(!(bool)$userUnSubscribed); 

     $form->handleRequest($request); 

     if ($form->isSubmitted() && $form->isValid()) { 
      /** 
      * @var $user User 
      */ 
      $user = $form->getData(); 

      /** @var UploadedFile $avatar */ 
      $avatar = $request->files->get('user_settings')['photo']; 

      $em = $this->getDoctrine()->getManager(); 

      if ($avatar) { 
       $avatar_content = file_get_contents($avatar->getRealPath()); 
       $avatarName = uniqid().'.jpg'; 
       $oldAvatar = $user->getPhoto(); 
       $user 
        ->setState(User::PHOTO_STATE_UNCHECKED) 
        ->setPhoto($avatarName); 
       $gearmanClient = $this->get('gearman.client'); 
       $gearmanClient->doBackgroundDependsOnEnv(
        'avatar_content_upload', 
        serialize(['content' => $avatar_content, 'avatarName' => $avatarName, 'oldAvatar' => $oldAvatar]) 
       ); 
      } 

      $subscribed = $form->get('subscribed')->getData(); 
      if ((bool)$userUnSubscribed && $subscribed) { 
       $em->remove($userUnSubscribed); 
      } elseif (!(bool)$userUnSubscribed && !$subscribed) { 
       $userUnSubscribed = new UserUnsubs(); 
       $userUnSubscribed->setEmail($form->get('email')->getData())->setTs(time()); 
       $em->persist($userUnSubscribed); 
      } 
      $user->setLastTs(time()); 
      $em = $this->getDoctrine()->getManager(); 
      $em->persist($user); 
      $em->flush(); 

      $this->get('user.manager')->refresh($user); 

      return $this->redirectToRoute('me'); 
     } 

     return $this->render(
      ':user:settings.html.twig', 
      [ 
       'form' => $form->createView(), 
      ] 
     ); 
    } 

UPD: to działa dobrze w przypadku zmiany w OAuthProvider:

/** 
* @param \Symfony\Component\Security\Core\User\UserInterface $user 
* 
* @return \Symfony\Component\Security\Core\User\UserInterface 
*/ 
public function refreshUser(UserInterface $user) 
{ 
    return $this->loadUserByUsername($user->getName()); 
} 

do:

/** 
* @param \Symfony\Component\Security\Core\User\UserInterface $user 
* 
* @return \Symfony\Component\Security\Core\User\UserInterface 
*/ 
public function refreshUser(UserInterface $user) 
{ 
    return $this->userManager($user->getId()); 
} 

ale wydaje się być brudne Hack .

Dzięki.

+1

czy możesz pokazać kontroler? –

+0

@AlessandroMinoccheri Dodałem kod kontrolera do pytania. – kRicha

+0

Dlaczego funkcja "refreshUser()" jest wywoływana, nawet jeśli adres e-mail jest nieprawidłowy? Dodaj więcej informacji o konfiguracji serurity.yml. – lordrhodos

Odpowiedz

1

Jest to podchwytliwe, dzięki repozytorium łatwiej było wyodrębnić problem. Użytkownik wiąże obiekt użytkownika z tokenem uwierzytelniania z metodą createForm(). Po wywołaniu wiadomość e-mail z obiektu użytkownika tokenu jest aktualizowana po wywołaniu.

Po raz pierwszy pomyślałem o rozwiązaniu tego problemu poprzez implementację EquatableInterface.html w jednostce User, ale to nie zadziałało, ponieważ porównany obiekt miał już ustawiony nieprawidłowy adres e-mail.

Może być również przydatne wdrożenie interfejsu EquatableInterface, który definiuje metodę sprawdzania, czy użytkownik jest równy bieżącemu użytkownikowi. Ten interfejs wymaga metody isEqualTo().)

Niż myślałem o wymuszeniu przeładowania użytkownika z bazy danych i zresetowaniu tokena zabezpieczającego, ale przyszło mi do głowy, że może wystarczyć odświeżenie bieżącego obiektu użytkownika z bazy danych w przypadku niepowodzenia formularza:

$this->get('doctrine')->getManager()->refresh($this->getUser());` 

W twoim kontrolerze rozwiąże to twój problem.

/** 
* @Route("/edit_me", name="edit") 
* @Security("has_role('ROLE_USER')") 
*/ 
public function editMyselfAction(Request $request) { 
    $form = $this->createForm(User::class, $this->getUser()); 

    if ($request->isMethod(Request::METHOD_POST)) { 
     $form->handleRequest($request); 
     if ($form->isSubmitted() && $form->isValid()) { 
      $user = $form->getData(); 
      $em = $this->getDoctrine()->getManager(); 
      $em->persist($user); 
      $em->flush(); 
     } else { 
      $this->get('doctrine')->getManager()->refresh($this->getUser()); 
     } 
    } 

    return $this->render(':security:edit.html.twig',['form' => $form->createView()]); 
} 

Alternatywne rozwiązanie

issue at the Symfony repository spowodowało jakiś cenny wkład około Avoiding Entities in Forms i Decoupling Your Security User która zapewnia bardziej kompleksowe podejście do rozwiązania problemu.

+0

dziękuję za uwagę, ale to jest brudny hack: D już napisałem problem do repozytorium symfony/symfony na github i przekazuję je mojemu repozytorium. To nie jest normalne zachowanie tokena. Mam już kolejny brudny hack, który został opisany w mojej odpowiedzi. Jeszcze raz dziękuję). – kRicha

+0

Cóż, szczerze mówiąc, nie uważam tego za brudny hak, ale za konieczne rozwiązanie, ponieważ sposób wiąże użytkownika $ z obiektu tokena do formularza. To jest oczekiwane zachowanie. Jeśli chcesz tego uniknąć, powinieneś utworzyć nowy pusty obiekt użytkownika, zainicjować go potrzebnymi danymi od aktualnie zalogowanego użytkownika i powiązać go z formularzem. Jeśli formularz jest poprawny, ręcznie odwzorujesz przesłany obiekt użytkownika na obiekt użytkownika z tokena. – lordrhodos

+0

tylko ze względu na kompletność. [Problem opublikowany w repozytorium symfony] (https://github.com/symfony/symfony/issues/23215) jest uważany za SRP, a nie za błąd. Jest to więc poprawna odpowiedź na twoje pytanie. – lordrhodos

3

Twój token użytkownika wydaje się być aktualizowany przez formularz, nawet jeśli ograniczenie adresu e-mail zatrzyma kolor.

Czy możesz sprawdzić, czy formularz za funkcją isValid? Możesz spróbować uniknąć tego za pomocą detektora zdarzeń lub weryfikatora.

Po zgłoszeniu zdarzenia powinieneś być w stanie sprawdzić integralność poczty e-mail, a następnie dodać FormError, aby uniknąć refreshUser.

+0

Czy przeczytałeś moje pytanie przed opublikowaniem odpowiedzi? – kRicha

+4

Czy mówisz poważnie? Rozumiem, dlaczego wciąż na tym polegasz, jesteśmy tutaj, aby ci pomóc za darmo, uprzejmie proszę. – fireaxe

+0

Wspomniałem już, że aktualizował się po przesłaniu formularza, także jeśli formularz nie jest prawidłowy. Jak widać w kodzie: 'if ($ form-> isSubmitted() && $ form-> isValid()) {' jest sprawdzanie walidatorów, i nie jest wypełnianie danych w encji, jeśli formularz jest nieprawidłowy. – kRicha