2012-11-06 10 views
8

Używam HWIOAuthBundle, aby umożliwić logowanie użytkownika z Oauth, utworzyłem niestandardowego dostawcę użytkownika, który tworzy użytkownika na wypadek, gdyby go nie było:Symfony2: Dokonaj pełnej rejestracji użytkownika po zalogowaniu, jeśli brakuje niektórych pól.

public function loadUserByOAuthUserResponse(UserResponseInterface $response) 
{ 
    $attr = $response->getResponse(); 
    switch($response->getResourceOwner()->getName()) { 
     case 'google': 
      if(!$user = $this->userRepository->findOneByGoogleId($attr['id'])) { 
       if(($user = $this->userRepository->findOneByEmail($attr['email'])) && $attr['verified_email']) { 
        $user->setGoogleId($attr['id']); 
        if(!$user->getFirstname()) { 
         $user->setFirstname($attr['given_name']); 
        } 
        if(!$user->getLastname()) { 
         $user->setLastname($attr['family_name']); 
        } 
        $user->setGoogleName($attr['name']); 
       }else{ 
        $user = new User(); 
        $user->setUsername($this->userRepository->createUsernameByEmail($attr['email'])); 
        $user->setEmail($attr['email']); 
        $user->setFirstname($attr['given_name']); 
        $user->setLastname($attr['family_name']); 
        $user->setPassword(''); 
        $user->setIsActive(true); 
        $user->setGoogleId($attr['id']); 
        $user->setGoogleName($attr['name']); 
        $user->addGroup($this->groupRepository->findOneByRole('ROLE_USER')); 
        $this->entityManager->persist($user); 
       } 
      } 
      break; 
     case 'facebook': 
      if(!$user = $this->userRepository->findOneByFacebookId($attr['id'])) { 
       if(($user = $this->userRepository->findOneByEmail($attr['email'])) && $attr['verified']) { 
        $user->setFacebookId($attr['id']); 
        if(!$user->getFirstname()) { 
         $user->setFirstname($attr['first_name']); 
        } 
        if(!$user->getLastname()) { 
         $user->setLastname($attr['last_name']); 
        } 
        $user->setFacebookUsername($attr['username']); 
       }else{ 
        $user = new User(); 
        $user->setUsername($this->userRepository->createUsernameByEmail($attr['email'])); 
        $user->setEmail($attr['email']); 
        $user->setFirstname($attr['first_name']); 
        $user->setLastname($attr['last_name']); 
        $user->setPassword(''); 
        $user->setIsActive(true); 
        $user->setFacebookId($attr['id']); 
        $user->setFacebookUsername($attr['username']); 
        $user->addGroup($this->groupRepository->findOneByRole('ROLE_USER')); 
        $this->entityManager->persist($user); 
       } 
      } 
      break; 
    } 

    $this->entityManager->flush(); 


    if (null === $user) { 
     throw new AccountNotLinkedException(sprintf("User '%s' not found.", $attr['email'])); 
    } 

    return $user; 
} 

Problem polega na tym, że twitter na przykład nie wysyła wiadomości e-mail lub chcę, aby dodatkowe pola zostały uwzględnione przed utworzeniem nowego użytkownika. Czy istnieje sposób przekierowania użytkownika do formularza "pełnej rejestracji" przed jego utworzeniem?

Próbowałem dodać detektor żądania, aby na każde żądanie, jeśli użytkownik jest zalogowany, sprawdza, czy e-mail tam jest, a jeśli nie, przekierowuje do strony complete_registration, ale przekieruje również, jeśli użytkownik przechodzi na stronę główną, wylogowuje się lub cokolwiek innego, chcę przekierować go tylko wtedy, gdy próbuje uzyskać dostęp do niektórych stron z ograniczeniami.

Albo lepiej, nie twórz go, dopóki nie poda wszystkich wymaganych informacji.

+0

@elnur co redagowałeś? żeby się dowiedzieć, czy coś było nie tak – alex88

+0

Kliknij na ostatni znacznik czasu edycji i przekonaj się sam. –

+0

Co za niegrzeczna odpowiedź, zły humor dzisiaj? – alex88

Odpowiedz

6

Znalazłem rozwiązanie przeze mnie, mam ręcznie stworzył nowy wyjątek:

<?php 

namespace Acme\UserBundle\Exception; 

use Symfony\Component\Security\Core\Exception\AuthenticationException; 
use HWI\Bundle\OAuthBundle\Security\Core\Exception\OAuthAwareExceptionInterface; 

/** 
* IncompleteUserException is thrown when the user isn't fully registered (e.g.: missing some informations). 
* 
* @author Alessandro Tagliapietra http://www.alexnetwork.it/ 
*/ 
class IncompleteUserException extends AuthenticationException implements OAuthAwareExceptionInterface 
{ 
    private $user; 
    private $accessToken; 
    private $resourceOwnerName; 

    /** 
    * {@inheritdoc} 
    */ 
    public function setAccessToken($accessToken) 
    { 
     $this->accessToken = $accessToken; 
    } 

    /** 
    * {@inheritdoc} 
    */ 
    public function getAccessToken() 
    { 
     return $this->accessToken; 
    } 

    /** 
    * {@inheritdoc} 
    */ 
    public function getResourceOwnerName() 
    { 
     return $this->resourceOwnerName; 
    } 

    /** 
    * {@inheritdoc} 
    */ 
    public function setResourceOwnerName($resourceOwnerName) 
    { 
     $this->resourceOwnerName = $resourceOwnerName; 
    } 

    public function setUser($user) 
    { 
     $this->user = $user; 
    } 

    public function getUser($user) 
    { 
     return $this->user; 
    } 

    public function serialize() 
    { 
     return serialize(array(
      $this->user, 
      $this->accessToken, 
      $this->resourceOwnerName, 
      parent::serialize(), 
     )); 
    } 

    public function unserialize($str) 
    { 
     list(
      $this->user, 
      $this->accessToken, 
      $this->resourceOwnerName, 
      $parentData 
     ) = unserialize($str); 
     parent::unserialize($parentData); 
    } 
} 

W ten sposób, w niestandardowy dostawca usług Oauth, gdy sprawdzam, czy istnieje użytkownik lub tworzę nowego użytkownika i sprawdzam, czy brakuje wymaganych pól:

if (!$user->getEmail()) { 
    $e = new IncompleteUserException("Your account doesn't has a mail set"); 
    $e->setUser($user); 
    throw $e; 
} 

W takim przypadku użytkownik zostanie przekierowany do formularza logowania, z tym wyjątkiem, w sesji, więc na stronie logowania zrobić:

if($error instanceof IncompleteUserException) { 
    $session->set(SecurityContext::AUTHENTICATION_ERROR, $error); 
    return $this->redirect($this->generateUrl('register_complete')); 
} 

a zostanie on przekierowany do formularza z użytkownikiem $ w wyjątku więc może prosić tylko o brakujące informacje, a następnie zalogować się do użytkownika.

+1

** To rozwiązanie nie jest zbyt eleganckie **, ale powinno działać. – mate64

1

Podczas migracji do strony sf wpadłem na podobny problem. Po migracji chciałem, aby zmigrowani użytkownicy uzupełnili swój profil, a nowo zarejestrowani użytkownicy mogli zacząć od razu.

Rozwiązałem to na podobieństwo twojego pomysłu, używając narzędzia RequestListener, ale dodałem białą listę stron, do której użytkownik jest uprawniony bez wypełniania swojego profilu. W zależności od liczby stron, do których użytkownik ma mieć dostęp bez wypełniania jego profilu, można również rozważyć użycie czarnej listy.

Nie sprawdziłem, czy w danym miejscu jest przekierowanie do strony zakończenia profilu, ale dodałem rolę "ROLE_MIGRATION" podczas migracji bazy danych users. W twoim przypadku możesz dodać rolę podczas tworzenia użytkownika za pomocą oauth.

Oto kod mojego żądania słuchacza:

public function onRequest(GetResponseEvent $evt) 
{ 

    if (HttpKernelInterface::MASTER_REQUEST !== $evt->getRequestType()) 
    { 
     return; 
    } 

    $token = $this->securityContext->getToken(); 

    if(!is_object($token)) or not migrating 
    { 
     // user is not logged in 
     return; 
    } 

    $user = $token->getUser(); 

    if(!$user instanceof User || !$user->hasRole('ROLE_MIGRATING')) 
    { 
     // different user class or already migrated 
     return; 
    } 

    $openPaths = array(
     '/start-2.0', 
     '/css', 
     '/js', 
     '/images', 
     '/media', 
     '/geo', 
     '/_wdt', 
     '/logout', or not migrating 
     '/terms', 
     '/contact', 
     '/about', 
     '/locale/set' 
    ); 

    foreach($openPaths as $p) 
    { 
     if(strpos($evt->getRequest()->getPathInfo(),$p)===0) 
     { 
      // path is open for migrating users 
      return; 
     } 
    } 



    header('Location: /start-2.0'); 
    exit; 
} 
+0

Myślę, że tworzenie wyjątku podczas logowania powinno być lepszym sposobem, zrobię kilka testów tej nocy i opublikuję odpowiedź jutro, jeśli dostanę coś dobrego! Ponieważ twoje podejście powinno być zmieniane za każdym razem, gdy dodajesz niektóre publiczne strony, a ja nie tylko przeprowadzam migrację, ale dziękuję za odpowiedź. – alex88

Powiązane problemy