2012-05-02 16 views
12

Sto lavorando a un'applicazione Symfony 2 in cui l'utente deve selezionare un profilo durante il processo di accesso.Controllo autenticazione manuale Symfony 2

Gli utenti possono avere profili multipli con cui lavorare e conoscono solo i propri profili. Quindi, per prima cosa, ho bisogno di chiedere username e password, se questi sono corretti, non dovrei accedere all'utente, ho bisogno di chiedere il profilo che user user durante la sessione.

Quindi, mostro un modulo con un nome utente e un campo password e lo invio utilizzando una richiesta Ajax, che risponde con la lista dei profili se nome utente e password sono corretti o un codice di errore in altro modo. Finalmente l'utente accede al sistema usando username, password e profilo.

Il problema è che non so come verificare se i dati di autenticazione sono corretti (utilizzando tutti i miei gestori di autenticazione, provider di utenti, ecc.) Per eseguire questo passaggio intermedio (prompt per profilo) senza in effetti registrare l'utente.

Qualcuno può aiutarmi con questo?

risposta

2

ho usato il codice da @Jordon e @Potor Polak per avvolgere la logica in un servizio autonomo che ha utilizzato il token di accesso corrente per convalidare la password. Forse alcuni ha bisogno di questo:

services.yml:

app.validator.manual_password: 
    class: AppBundle\Service\ManualPasswordValidator 
    arguments: 
     - '@security.token_storage' 
     - '@security.encoder_factory' 

ManualPasswordValidator.php:

<?php 

namespace AppBundle\Service; 

use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage; 
use Symfony\Component\Security\Core\Encoder\EncoderFactory; 

/** 
* Class ManualPasswordValidator 
* 
* @package AppBundle\Service 
*/ 
class ManualPasswordValidator 
{ 
    /** 
    * @var EncoderFactory 
    */ 
    protected $encoderFactory; 

    /** 
    * @var TokenStorage 
    */ 
    protected $tokenStorage; 

    /** 
    * ManualPasswordValidator constructor. 
    * 
    * @param EncoderFactory $encoderFactory 
    * @param TokenStorage $tokenStorage 
    */ 
    public function __construct(TokenStorage $tokenStorage, EncoderFactory $encoderFactory) 
    { 
     $this->encoderFactory = $encoderFactory; 
     $this->tokenStorage = $tokenStorage; 
    } 

    /** 
    * @param $password 
    * @return bool 
    */ 
    public function passwordIsValidForCurrentUser($password) 
    { 
     $token = $this->tokenStorage->getToken(); 

     if ($token) { 
      $user = $token->getUser(); 

      if ($user) { 
       $encoder = $this->encoderFactory->getEncoder($user); 

       if ($encoder->isPasswordValid($user->getPassword(), $password, $user->getSalt())) { 
        return true; 
       } 
      } 
     } 

     return false; 
    } 
} 

Dopo questo si può iniettare il ManualPasswordValidator dove vuoi e utilizzarlo come:

$password  = $request->get('password'); 
$passwordIsValid = $this->manualPasswordValidator->passwordIsValidForCurrentUser($password); 
16

Si potrebbe fare qualcosa di simile per recuperare l'utente e verificare manualmente la password -

$username = trim($this->getRequest()->query->get('username')); 
$password = trim($this->getRequest()->query->get('password')); 

$em = $this->get('doctrine')->getEntityManager(); 
$query = $em->createQuery("SELECT u FROM \Some\Bundle\Entity\User u WHERE u.username = :username"); 
$query->setParameter('username', $username); 
$user = $query->getOneOrNullResult(); 

if ($user) { 
    // Get the encoder for the users password 
    $encoder_service = $this->get('security.encoder_factory'); 
    $encoder = $encoder_service->getEncoder($user); 
    $encoded_pass = $encoder->encodePassword($password, $user->getSalt()); 

    if ($user->getPassword() == $encoded_pass) { 
    // Get profile list 
    } else { 
    // Password bad 
    } 
} else { 
    // Username bad 
} 

Una volta che hai il tuo profilo indietro dal client, è possibile eseguire manualmente il login nel controller del server AJAX abbastanza facilmente troppo -

// Get the security firewall name, login 
$providerKey = $this->container->getParameter('fos_user.firewall_name'); 
$token = new UsernamePasswordToken($user, $password, $providerKey, $user->getRoles()); 
$this->get("security.context")->setToken($token); 

// Fire the login event 
$event = new InteractiveLoginEvent($this->getRequest(), $token); 
$this->get("event_dispatcher")->dispatch("security.interactive_login", $event); 

potrebbe aver bisogno di un paio di righe di utilizzo -

use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; 
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent; 
+1

Sono fermamente consiglia di guardare la soluzione @Piotr Polak poiché funziona con al l codificatori di password. –

+0

Non modificare la risposta per cambiarla completamente. Invece, upvotare la risposta giusta. – Alsciende

1

L'unico modo per autenticare i miei utenti su un controller è effettuare un sottorequest e quindi reindirizzare. Ecco il mio codice, sto usando selce ma si può facilmente adattarlo alle Symfony2:

$subRequest = Request::create($app['url_generator']->generate('login_check'), 'POST', array('_username' => $email, '_password' => $password, $request->cookies->all(), array(), $request->server->all()); 

$response = $app->handle($subRequest, HttpKernelInterface::MASTER_REQUEST, false); 

return $app->redirect($app['url_generator']->generate('curriculos.editar')); 
30

Un problema con @ codice di Jordon è che non funziona con algoritmi di hashing che generano hash diversi per la stessa password (come bcrypt che racconta internamente i suoi parametri, sia il numero di iterazioni che il sale). È più corretto utilizzare isPasswordValid dell'Encoder per confrontare le password.

Ecco il codice migliore che funziona bene con bcrypt:

$username = trim($this->getRequest()->query->get('username')); 
$password = trim($this->getRequest()->query->get('password')); 

$em = $this->get('doctrine')->getManager(); 
$query = $em->createQuery("SELECT u FROM \Some\Bundle\Entity\User u WHERE u.username = :username"); 
$query->setParameter('username', $username); 
$user = $query->getOneOrNullResult(); 

if ($user) { 
    // Get the encoder for the users password 
    $encoder_service = $this->get('security.encoder_factory'); 
    $encoder = $encoder_service->getEncoder($user); 

    // Note the difference 
    if ($encoder->isPasswordValid($user->getPassword(), $password, $user->getSalt())) { 
    // Get profile list 
    } else { 
    // Password bad 
    } 
} else { 
    // Username bad 
}