2012-05-02 39 views
12

Pracuję nad aplikacją Symfony 2, w której użytkownik musi wybrać profil podczas procesu logowania.Ręczna kontrola autentyczności Symfony 2

Użytkownicy mogą mieć wiele profilów do pracy i znają tylko własne profile. Tak więc najpierw muszę zapytać o nazwę użytkownika i hasło, jeśli są one poprawne, nie powinienem logować się do użytkownika, muszę poprosić o profil użytkownika, którego będzie używał użytkownik podczas sesji.

Tak więc, pokazuję formularz z polem nazwa użytkownika i hasło i wysyłam go za pomocą żądania Ajax, które to żądanie odpowiada z listą profili, jeśli nazwa użytkownika i hasło są poprawne lub inaczej kod błędu. Wreszcie użytkownik loguje się do systemu przy użyciu nazwy użytkownika, hasła i profilu.

Problem polega na tym, że nie wiem, jak sprawdzić, czy dane uwierzytelniające są poprawne (przy użyciu wszystkich moich menedżerów uwierzytelniania, dostawców użytkowników itp.), Aby wykonać ten etap pośredni (monituje o profil) bez faktycznego logowania użytkownika.

Czy ktoś może mi w tym pomóc?

Odpowiedz

2

użyłem kodu z @Jordon i @Potor Polak zawinąć logikę w autonomicznym usług, które wykorzystał obecny token dostępu, aby potwierdzić hasło. Może niektórzy tego potrzebuje:

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

Po tym można wstrzyknąć ManualPasswordValidator gdzie chcesz i używać go jak:

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

Można zrobić coś takiego, aby odzyskać użytkownika i hasło ręcznie przetestować -

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

Gdy masz swój profil z powrotem od klienta, można przeprowadzić logowanie ręcznie w sterowniku serwera AJAX dość łatwo też -

// 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); 

może potrzebować kilku użytku linie -

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

gorąco radzę przyjrzeć się rozwiązaniu @Piotr Polak, ponieważ działa z al l enkoderów hasła. –

+0

Nie edytuj odpowiedzi, aby całkowicie ją zmienić. Zamiast tego przekaż właściwą odpowiedź. – Alsciende

1

Jedynym sposobem, w jaki mogę uwierzytelnić moich użytkowników na kontrolerze, jest subskrypcja, a następnie przekierowanie. Tu jest mój kod, używam SILEX ale łatwo można ją dostosować do 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

Problem z @ kodu Jordan jest to, że nie będzie współpracować z algorytmów haszowania które generują różne mieszań dla tego samego hasła (takie jak bcrypt, który wewnętrznie opisze swoje parametry, zarówno liczbę iteracji, jak i sól). Bardziej poprawne jest użycie isPasswordValid z Encoder do porównywania haseł.

Oto poprawiony kod, który działa dobrze z 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 
}