2012-11-06 8 views
8

Sto utilizzando HWIOAuthBundle per consentire a un utente di accedere con Oauth, ho creato un fornitore utente personalizzato che crea un utente nel caso non esista:Symfony2: consente agli utenti di completare la registrazione dopo l'accesso se mancano alcuni campi

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; 
} 

il problema è che Twitter per esempio non dà la e-mail o voglio alcuni campi aggiuntivi da inserire prima di creare un nuovo utente. C'è un modo per reindirizzare un utente a un modulo di "registrazione completa" prima di crearlo?

ho cercato di aggiungere una richiesta di ascoltatore, che su ogni richiesta, se l'utente è connesso, controlla se l'email è lì e se non lo fa reindirizza alla pagina complete_registration, ma sarà reindirizzare anche se l'utente va alla homepage, per uscire o qualsiasi altra cosa, lo voglio reindirizzare solo se tenta di accedere ad alcune pagine riservate dell'utente.

O meglio, non crearlo finché non fornisce tutte le informazioni richieste.

+0

@elnur cosa hai modificato? solo per sapere se c'era qualcosa di sbagliato – alex88

+0

Fai clic sull'ultimo timestamp di modifica e guarda tu stesso. –

+0

Che risposta scortese, cattivo umore oggi eh? – alex88

risposta

6

ho trovato la soluzione da me, ho creato manualmente una nuova eccezione:

<?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); 
    } 
} 

In questo modo, nel utente utente Oauth personalizzato quando controllo se un utente esiste o creo un nuovo utente controllo se mancano i campi richiesti:

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

In questo caso l'utente verrà reindirizzato al form di login, con questa eccezione in sessione, quindi nella pagina di login che faccio:

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

E sarà reindirizzato a un modulo con l'utente $ nell'eccezione quindi può chiedere solo le informazioni mancanti e quindi accedere all'utente.

+1

** Questa soluzione non è molto elegante **, ma dovrebbe funzionare. – mate64

1

Ho riscontrato un problema simile durante la migrazione a un sito sf. Dopo la migrazione, volevo che gli utenti migrati completassero il loro profilo mentre gli utenti appena registrati potevano iniziare immediatamente.

Ho risolto questo simile alla tua idea usando un RequestListener ma ho aggiunto una whitelist di pagine che l'utente è autorizzato a completare il suo profilo. A seconda del numero di pagine a cui l'utente può accedere senza completare il suo profilo, potresti anche considerare l'utilizzo di una lista nera.

Non ho verificato la presenza di un campo particolare che sta eseguendo il reindirizzamento alla pagina di completamento del profilo ma ha aggiunto un ruolo "ROLE_MIGRATION" durante la migrazione del database degli utenti. Nel tuo caso puoi aggiungere il ruolo quando crei l'utente tramite oauth.

Ecco il codice della mia richiesta ascoltatore:

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

Penso che la creazione di un'eccezione durante l'accesso dovrebbe essere un modo migliore, effettuerò alcuni test questa sera e pubblicherò una risposta domani se ottengo qualcosa di buono! Perché il tuo approccio dovrebbe essere cambiato ogni volta che aggiungi alcune pagine pubbliche e non sto solo eseguendo una migrazione, ma grazie per la risposta .. – alex88

Problemi correlati