Autenticazione utente automatica dopo la logging

Stiamo costruendo un'app business partendo da zero in Symfony 2, e mi sono imbattuto in un po 'di difficoltà con il stream di logging degli utenti: dopo che l'utente ha creato un account, dovrebbero essere automaticamente connessi con quelle credenziali, invece di essere immediatamente costretto a fornire nuovamente le proprie credenziali.

Qualcuno ha avuto qualche esperienza con questo, o in grado di indicarmi la giusta direzione?

Symfony 2.6.x – Symfony 3.0.x

A partire da symfony 2.6 security.context è deprecato a favore di security.token_storage . Il controller ora può essere semplicemente:

 use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use YourNameSpace\UserBundle\Entity\User; class LoginController extends Controller{ public function registerAction() { $user = //Handle getting or creating the user entity likely with a posted form $token = new UsernamePasswordToken($user, null, 'main', $user->getRoles()); $this->get('security.token_storage')->setToken($token); $this->get('session')->set('_security_main', serialize($token)); } } 

Anche se questo è deprecato, puoi comunque usare security.context come è stato fatto per essere compatibile con le versioni precedenti. Basta essere pronti ad aggiornarlo per Symfony 3

Puoi leggere ulteriori informazioni sulle 2.6 modifiche per la sicurezza qui: https://github.com/symfony/symfony/blob/2.6/UPGRADE-2.6.md

Symfony 2.3.x

Per get questo risultato in symfony 2.3 non è più ansible semplicemente impostare il token nel context di sicurezza. È inoltre necessario salvare il token nella session.

Supponendo un file di sicurezza con un firewall come:

 // app/config/security.yml security: firewalls: main: //firewall settings here 

E anche un'azione controller simile:

 use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use YourNameSpace\UserBundle\Entity\User; class LoginController extends Controller{ public function registerAction() { $user = //Handle getting or creating the user entity likely with a posted form $token = new UsernamePasswordToken($user, null, 'main', $user->getRoles()); $this->get('security.context')->setToken($token); $this->get('session')->set('_security_main',serialize($token)); //Now you can redirect where ever you need and the user will be logged in } } 

Per la creazione di token, è necessario creare un UsernamePasswordToken , che accetta 4 parametri: Entità utente, Credenziali utente, Nome firewall, Ruoli utente. Non è necessario fornire le credenziali dell'utente affinché il token sia valido.

Non sono sicuro al 100% che l'impostazione del token su security.context sia necessaria se stai per redirect immediatamente. Ma non sembra ferire quindi l'ho lasciato.

Quindi la parte importnte, impostando la variabile di session. La convenzione di denominazione delle variables è _security_ seguita dal nome del firewall, in questo caso main fa _security_main

Ho capito questo, finalmente.

Dopo la logging dell'utente, dovresti avere accesso a un'istanza dell'object di qualsiasi cosa tu abbia impostato come entity framework; utente nella configuration del tuo provider. La soluzione è creare un nuovo token con quell'entity framework; utente e passarlo nel context di sicurezza. Ecco un esempio basato sulla mia configuration:

RegistrationController.php:

 $token = new UsernamePasswordToken($userEntity, null, 'main', arrays('ROLE_USER')); $this->get('security.context')->setToken($token); 

Dove main è il nome del firewall per la tua applicazione (grazie, @Joe). Questo è davvero tutto quello che c'è da fare; il sistema ora considera il tuo utente completamente connesso come l'utente che ha appena creato.

EDIT: per il commento di @ Miquel, ho aggiornato l'esempio del codice del controller per includere un ruolo predefinito ragionevole per un nuovo utente (anche se ovviamente questo può essere regolato in base alle esigenze specifiche dell'applicazione).

Sto usando Symfony 2.2 e la mia esperienza è stata leggermente diversa da quella di Problematic , quindi questa è una versione combinata di tutte le informazioni di questa domanda più alcune delle mie.

Penso che Joe abbia torto sul valore di $providerKey , il terzo parametro del constructor UsernamePasswordToken . Dovrebbe essere la chiave di un provider di authentication (non utente). Viene utilizzato dal sistema di authentication per distinguere tra token creati per provider diversi. Qualsiasi provider che discende da UserAuthenticationProvider eseguirà solo autenticazioni di token la cui chiave del provider corrisponde alla sua. Ad esempio, UsernamePasswordFormAuthenticationListener imposta la chiave del token che crea per corrispondere a quella del relativo DaoAuthenticationProvider corrispondente. Ciò consente a un singolo firewall di disporre di più provider di nome utente e password senza che questi si calpestino l'un l'altro. Pertanto, dobbiamo scegliere una chiave che non sia in conflitto con altri fornitori. Io uso 'new_user' .

Ho alcuni sisthemes in altre parti della mia applicazione che dipendono dall'evento di successo dell'authentication e che non viene triggersto semplicemente impostando il token nel context. Ho dovuto prendere EventDispatcher dal container e sparare manualmente l'evento. Ho deciso anche di triggersre un evento di accesso interattivo perché stiamo autenticando l'utente implicitamente, non in risposta a una richiesta di accesso esplicita.

 use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; use Symfony\Component\Security\Core\AuthenticationEvents; use Symfony\Component\Security\Core\Event\AuthenticationEvent; $user = // get a Symfony user instance somehow $token = new UsernamePasswordToken( $user, null, 'new_user', $user->getRoles() ); $this->get( 'security.context' )->setToken( $token ); $this->get( 'event_dispatcher' )->dispatch( AuthenticationEvents::AUTHENTICATION_SUCCESS, new AuthenticationEvent( $token ) ); 

Nota che l'uso di $this->get( .. ) presuppone che lo snippet sia in un metodo controller. Se stai usando il codice da qualche altra parte, dovrai cambiarlo per call ContainerInterface::get( ... ) in un modo appropriato per l'ambiente. Come succede, le mie entity framework; utente implementano UserInterface modo che io possa usarle direttamente con il token. Se i tuoi non dovresti trovare un modo per convertirli in istanze UserInterface .

Quel codice funziona, ma mi sembra che stia hackerando l'architettura di authentication di Symfony piuttosto che lavorare con esso. Sarebbe probabilmente più corretto implementare un nuovo provider di authentication con una propria class di token anziché dirottare UsernamePasswordToken . Inoltre, l'utilizzo di un fornitore appropriato significherebbe che gli events sono stati gestiti per te.

Se si dispone di un object UserInterface (e dovrebbe essere il caso per la maggior parte del tempo), si potrebbe voler utilizzare la function getRoles implementata per l'ultimo argomento. Quindi, se crei una function logUser, dovrebbe apparire così:

 public function logUser(UserInterface $user) { $token = new UsernamePasswordToken($user, null, 'main', $user->getRoles()); $this->container->get('security.context')->setToken($token); } 

Nel caso qualcuno abbia la stessa domanda di follow-on che mi ha fatto tornare qui:

chiamata

 $this->container->get('security.context')->setToken($token); 

effettua solo l'attuale security.context per la rotta utilizzata.

Ad esempio, è ansible accedere a un utente da un URL all'interno del controllo del firewall.

(Aggiungi un'exception per il path, se necessario, IS_AUTHENTICATED_ANONYMOUSLY )

Come già menzionato in Problematic, questo elusivo parametro $ providerKey non è in realtà altro che il nome della regola del firewall, 'foobar' nel caso dell'esempio sotto.

 firewalls: foobar: pattern: /foo/ 

Ho provato tutte le risposte qui e nessuno ha funzionato. L'unico modo per autenticare i miei utenti su un controller è effettuare un sottorequest e quindi redirect. Ecco il mio codice, sto usando silex ma puoi facilmente adattarlo a symfony2:

 $subRequest = Request::create($app['url_generator']->generate('login_check'), 'POST', arrays('_username' => $email, '_password' => $password, $request->cookies->all(), arrays(), $request->server->all()); $response = $app->handle($subRequest, HttpKernelInterface::MASTER_REQUEST, false); return $app->redirect($app['url_generator']->generate('curriculos.editar')); 

Su Symfony versione 2.8.11 (probabilmente funzionante per versioni precedenti e nuove), se si utilizza FOSUserBundle è sufficiente fare questo:

 try { $this->container->get('fos_user.security.login_manager')->loginUser( $this->container->getParameter('fos_user.firewall_name'), $user, null); } catch (AccountStatusException $ex) { // We simply do not authenticate users which do not pass the user // checker (not enabled, expired, etc.). } 

Non c'è bisogno di submit events come ho visto in altre soluzioni.

viene generato da FOS \ UserBundle \ Controller \ RegistrationController :: authenticateUser

(da composer.json FOSUserBundle version: "friendsofsymfony / user-bundle": "~ 1.3")