2014-12-27 19 views
6

Sto cercando di combinare FOSUserBundle e HWIOAuthBundle seguendo articoli come https://gist.github.com/danvbe/4476697. Tuttavia, non desidero la registrazione automatica dei nuovi utenti autenticati da OAuth2: ulteriori informazioni dovrebbero essere fornite dall'utente.Registrazione FOSUserBundle e HWIOAuthBundle

risultato desiderato

lo farei per esempio vogliono le seguenti informazioni per un utente registrato:

  • (Nome utente, anche se preferirei basta usare e-mail) nome
  • display (obbligatorio)
  • Foto del profilo (obbligatorio)
  • Indirizzo di posta elettronica (obbligatorio se non si utilizza Facebook)
  • Password (obbligatorio se no Facebook-id)
  • Facebook-id (obbligatorio se nessun indirizzo di posta elettronica)

Ora, quando un utente si autentica tramite Facebook e l'utente non esiste ancora, voglio una registrazione modulo per compilare le informazioni mancanti (nome visualizzato e immagine del profilo). Solo dopo questo, dovrebbe essere creato il nuovo FOSUser. Nella maggior parte delle esercitazioni, campi come l'immagine del profilo e l'indirizzo e-mail vengono automaticamente popolati con le informazioni di Facebook. Questo non è sempre desiderabile né possibile.

Inoltre, pensa a cose come accettare i Termini di accordo e le regole che desideri mostrare prima che l'utente venga creato.

possibili approcci

Una soluzione potrebbe essere, credo, per creare un nuovo tipo di-AnonymousToken, l'OAuthenticatedToken, che detiene il relativo informazioni OAuth2 ma non conta un authenticaton. Quindi, fai in modo che tutte le pagine controllino questo tipo di autenticazione e lasci che altre pagine reindirizzino alla pagina di registrazione OAuth. Tuttavia, questa mi sembra una soluzione inutilmente complicata.

Un'altra soluzione potrebbe essere probabilmente scrivere il codice da zero e non utilizzare i due pacchetti menzionati. Spero davvero che questo non sia necessario.

D: Come posso inserire il codice di completamento registrazione nel resto del flusso di accesso?

(Mi piacerebbe condividere un po 'di codice, ma dal momento che è il concetto a cui ho bisogno di aiuto, non ho molto da mostrare.)

Edit: Soluzione

seguito adivce di Derick, ho avuto le basi di lavoro in questo modo:

Il fornitore di utente personalizzato salva le informazioni (purtroppo, non ha accesso al token cruda quindi non posso ancora il login l'utente dopo la registrazione): gestore di fallimento

class UserProvider extends FOSUBUserProvider { 

    protected $session; 

    public function __construct(Session $session, UserManagerInterface $userManager, array $properties) { 
     $this->session = $session; 
     parent::__construct($userManager, $properties); 
    } 

    public function loadUserByOAuthUserResponse(UserResponseInterface $response) 
    { 
     try { 
      return parent::loadUserByOAuthUserResponse($response); 
     } 
     catch (AccountNotLinkedException $e) { 
      $this->session->set('oauth.resource', $response->getResourceOwner()->getName()); 
      $this->session->set('oauth.id', $response->getResponse()['id']); 
      throw $e; 
     } 
    } 

} 

personalizzato:

<?php 
// OAuthFailureHandler.php 
class OAuthFailureHandler implements AuthenticationFailureHandlerInterface { 

    public function onAuthenticationFailure(Request $request, AuthenticationException $exception) { 

     if (!$exception instanceof AccountNotLinkedException) { 
      throw $exception; 
     } 

     return new RedirectResponse('fb-register'); 

    } 

} 

Entrambi sono registrato come un servizio:

# services.yml 
services: 
    app.userprovider: 
     class: AppBundle\Security\Core\User\UserProvider 
     arguments: [ "@session", "@fos_user.user_manager", {facebook: facebookID} ] 
    app.oauthfailurehandler: 
     class: AppBundle\Security\Handler\OAuthFailureHandler 
     arguments: ["@security.http_utils", {}, "@service_container"] 

e configurato in config di sicurezza:

# security.yml 
security: 
    providers: 
     fos_userbundle: 
      id: fos_user.user_provider.username_email 
    firewalls: 
     main: 
      form_login: 
       provider:   fos_userbundle 
       csrf_provider:  form.csrf_provider 
       login_path:   /login 
       check_path:   /login_check 
       default_target_path: /profile 
      oauth: 
       login_path:   /login 
       check_path:   /login_check 
       resource_owners: 
        facebook:  hwi_facebook_login 
       oauth_user_provider: 
        service:   app.userprovider 
       failure_handler:  app.oauthfailurehandler 
      anonymous: true 
      logout: 
       path:   /logout 
       target:   /login 

A/fb-registrarsi, ho lasciato all'utente di inserire un nome utente e salvare l'utente stesso:

/** 
* @Route("/fb-register", name="hwi_oauth_register") 
*/ 
public function registerOAuthAction(Request $request) { 

    $session = $request->getSession(); 

    $resource = $session->get('oauth.resource'); 
    if ($resource !== 'facebook') { 
     return $this->redirectToRoute('home'); 
    } 

    $userManager = $this->get('fos_user.user_manager'); 
    $newUser = $userManager->createUser(); 

    $form = $this->createForm(new RegisterOAuthFormType(), $newUser); 
    $form->handleRequest($request); 

    if ($form->isValid()) { 

     $newUser->setFacebookId($session->get('oauth.id')); 
     $newUser->setEnabled(true); 

     $userManager->updateUser($newUser); 

     try { 
      $this->container->get('hwi_oauth.user_checker')->checkPostAuth($newUser); 
     } catch (AccountStatusException $e) { 
      // Don't authenticate locked, disabled or expired users 
      return; 
     } 

     $session->remove('oauth.resource'); 
     $session->remove('oauth.id'); 
     $session->getFlashBag() 
      ->add('success', 'You\'re succesfully registered!'); 

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

    return $this->render('default/register-oauth.html.twig', array(
     'form' => $form->createView() 
    )); 

} 

L'utente non ha effettuato il login in seguito, il che è un peccato. Inoltre, la normale funzionalità di fosub (modifica del profilo, modifica della password) non funziona più immediatamente.

Sto semplicemente usando il nome utente come displayname, non sono sicuro del motivo per cui non l'ho visto prima.

+0

Hai trovato la soluzione? Per lo più: –

+0

; L'ho modificato nella domanda e sembra funzionare quasi come desiderato. E 'stato un po' di tempo però, non so esattamente come è finita. – TacoV

risposta

0

Passaggio 1: Creare il proprio provider utente. Estendi OAuthUserProvider e personalizza le tue esigenze. Se l'utente ha eseguito correttamente l'apertura, genera un'eccezione specifica (probabilmente l'accountnotlinkedException) e pubblica tutti i dati relativi all'accesso da qualche parte

Passaggio 2: Crea il proprio gestore di errori di autenticazione. Verifica che l'errore generato sia quello specifico che hai lanciato nel passaggio 1. Qui potrai reindirizzare a tuo nome nella pagina di informazioni aggiuntive.

Questo è come registrare voi gestori personalizzati:

#security.yml 
firewall: 
    main: 
     oauth: 
      success_handler: authentication_handler 
      failure_handler: social_auth_failure_handler 

#user bundle services.yml (or some other project services.yml) 
services: 
    authentication_handler: 
     class: ProjectName\UserBundle\Handler\AuthenticationHandler 
     arguments: ["@security.http_utils", {}, "@service_container"] 
     tags: 
      - { name: 'monolog.logger', channel: 'security' } 

    social_auth_failure_handler: 
     class: ProjectName\UserBundle\Handler\SocialAuthFailureHandler 
     arguments: ["@security.http_utils", {}, "@service_container"] 
     tags: 
      - { name: 'monolog.logger', channel: 'security' } 

Fase 3: Crea il pieno nella pagina di informazioni aggiuntive. Estrarre tutti i dati rilevanti che sono stati salvati nel passaggio 1 e creare l'utente se tutto viene eseguito.

+0

Sembra buono. Sto estendendo FOSUBUserProvider, che estende già OAuthUserProvider e lancia l'AccountNotLinkedException. Mi blocco comunque al punto 2; come si fa e si registra il proprio gestore degli errori di autenticazione? Non ho potuto impostare il gestore fallito senza un passaggio del compilatore (che sembrava eccessivo). Ho provato a impostare il parametro hwi_oauth.authentication.listener.oauth.class sulla mia classe (estendendo OAuthListener). Il metodo onFailure è privato, come la variabile failureHandler. Continuerò a provare e riferirò indietro se trovo qualcosa. – TacoV

+0

@TacoV ho aggiunto alcuni esempi di configurazione. Chiedi ai tuoi gestori di estendere DefaultAuthenticationFailureHandler o DefaultAuthenticationSuccessHandler rispettivamente –

+0

Grazie, questo era il suggerimento di cui avevo bisogno. La domanda principale (come iniettare il reindirizzamento ecc.) Ora ha una risposta, grazie mille!Quando avrò un esempio operativo completo, lo modificherò nella domanda. – TacoV