2012-05-02 74 views
12

我工作的一個Symfony的2應用中,用戶必須在登錄過程中選擇配置文件。手冊認證檢查Symfony的2

用戶可能有數倍型材工作,他們只知道自己的配置文件。所以首先,我需要提示輸入用戶名和密碼,如果這些都是正確的,我不應該登錄用戶,我需要提示用戶在會話期間使用的個人資料。

所以,我告訴用戶名和密碼字段的表單,並使用一個Ajax請求發送時,該請求與配置文件列表進行響應,如果用戶名和密碼是否正確或其他錯誤代碼。最後,用戶使用用戶名,密碼和配置文件登錄系統。

問題是我不知道如何檢查身份驗證數據是否正確(使用我所有的身份驗證管理器,用戶提供程序等)來完成此中間步驟(提示配置文件)而事實上不記錄用戶。

任何人都可以幫助我嗎?

回答

2

我使用的代碼從@Jordon@Potor Polak包裹,所使用的當前訪問令牌以驗證密碼的獨立服務的邏輯。也許一些需要這樣的:

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

在這之後,你可以注入ManualPasswordValidator無論你想用它喜歡:

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

你可以做這樣的事情來獲取用戶和手動測試密碼 -

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

一旦你得到了你的個人資料從客戶端回,你可以在AJAX服務器控制器進行手動登錄容易夠得 -

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

可能需要幾行使用 -

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

我強烈建議查看@Piotr Polak解決方案,因爲它可以與al l密碼編碼器。 –

+0

不要編輯答案以完全更改它。相反,upvote正確的答案。 – Alsciende

1

我可以在控制器上驗證用戶的唯一方法是創建子請求,然後重定向。這裏是我的代碼,我使用的硅石,但你可以很容易地適應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

與@喬丹的代碼的問題是,它不會與產生了相同的密碼不同的哈希散列算法的工作(比如將故事內部的參數加密,迭代次數和鹽)。使用Encoder的isPasswordValid來比較密碼更爲正確。

這裏是改進的代碼,正常工作與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 
}