2017-03-09 62 views
0

事情,我們希望在我們的應用中實現是:Symfony的3 FosUserBundle非唯一的用戶名登錄

  • 非唯一的用戶名[完成]
  • 唯一的用戶名和電子郵件相結合
  • FosUserBundle將獲取所有用戶(在用戶登錄)與給定的用戶名和檢查是否有任何用戶有給定的密碼(散列與bcrypt)。當找到用戶時,它會將用戶登錄。

通過覆蓋用戶ORM中的用戶名字段,使用戶名不唯一很簡單。但是我們仍然堅持如何着手實現最後兩點。我們已經開始創建一個自定義的用戶提供程序,但似乎Symfony Security只能處理一個用戶(名稱)。

有沒有人有經驗可以幫助我們?如果您需要更多信息或代碼片段,請詢問。先謝謝你!

+1

IMO你不應該使用FOSUserBundle來實現這一點,你應該創建你自己的UserBundle。 – Shady

+0

我們目前正在考慮實施我們自己的Guard系統,它似乎與FOSUserBundle很好地協同工作,並且在我們發言時它會一起工作。資料來源:http://symfony.com/doc/current/security/guard_authentication.html –

+2

如果兩個具有相同用戶名的人共享相同的密碼? – kero

回答

1

因此,通過查看Symfony安全模塊的大量文檔後,我們發現了它。

我們爲User模型添加了一個額外的字段(displayname),因爲Symfony完全圍繞用戶名是Unique的這一事實構建。它總是使用給定的用戶名獲取第一個用戶,這不是我們想要的。因此,我們開始編寫我們自己的Guard認證系統,雖然我們必須做出一些調整,但這非常簡單。 這一切運行良好,但我們遇到了內置UsernamePasswordFormAuthenticationListener的問題,此偵聽器仍然從登錄表單中獲取顯示名稱。我們實際上需要唯一的用戶名,以便Symfony知道要使用哪個用戶。

我們創建了一個擴展標準偵聽器的自定義偵聽器,並確保用戶名不是從登錄表單中,而是從用戶令牌中獲取的。

所以我們的流程現在是這樣的:用戶填寫他的用戶名(實際上他的顯示名稱)和密碼,系統獲取具有該顯示名稱的所有用戶。然後我們循環這些用戶並檢查是否有人擁有該密碼。如果是這樣,請認證用戶。 在用戶創建管理員填寫顯示名稱和系統將自動增加這作爲用戶名。 (admin_1,admin_2,...)。

我們必須監視@kero說的是真的,但是對於Bcrypt,它似乎即使使用簡單的密碼(如「123」),也會爲每個用戶產生不同的散列值。

唯一剩下的就是在顯示名稱和電子郵件的唯一組合上有一個UniqueConstraint。如果有人知道如何在我們的orm.xml和form中實現這一點,謝謝。

http://symfony.com/doc/current/security/guard_authentication.html

定製衛隊驗證器

class Authenticator extends AbstractGuardAuthenticator 
{ 
    private $encoderFactory; 
    private $userRepository; 
    private $tokenStorage; 
    private $router; 

public function __construct(EncoderFactoryInterface $encoderFactory, UserRepositoryInterface $userRepository, TokenStorageInterface $tokenStorage, Router $router) 
{ 
    $this->encoderFactory = $encoderFactory; 
    $this->userRepository = $userRepository; 
    $this->tokenStorage = $tokenStorage; 
    $this->router = $router; 
} 

/** 
* Called on every request. Return whatever credentials you want, 
* or null to stop authentication. 
*/ 
public function getCredentials(Request $request) 
{ 
    $encoder = $this->encoderFactory->getEncoder(new User()); 
    $displayname = $request->request->get('_username'); 
    $password = $request->request->get('_password'); 

    $users = $this->userRepository->findByDisplayname($displayname); 

    if ($users !== []) { 
     foreach ($users as $user) { 
      if ($encoder->isPasswordValid($user->getPassword(), $password, $user->getSalt())) { 
       return ['username' => $user->getUsername(), 'password' => $user->getPassword()]; 
      } 
     } 
    } else { 
     if ($this->tokenStorage->getToken() !== null) { 
      $user = $this->tokenStorage->getToken()->getUser(); 

      return ['username' => $user->getUsername(), 'password' => $user->getPassword()]; 
     } 
    } 

    return null; 
} 

public function getUser($credentials, UserProviderInterface $userProvider) 
{ 
    if ($credentials !== null) { 
     return $userProvider->loadUserByUsername($credentials["username"]); 
    } 

    return null; 
} 

public function checkCredentials($credentials, UserInterface $user) 
{ 
    if ($user !== null) { 
     return true; 
    } else { 
     return false; 
    } 
} 

public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey) 
{ 
    return null; 
} 

public function onAuthenticationFailure(Request $request, AuthenticationException $exception) 
{ 
    $exclusions = ['/login']; 

    if (!in_array($request->getPathInfo(), $exclusions)) { 
     $request->getSession()->set(Security::AUTHENTICATION_ERROR, $exception); 
     throw $exception; 
    } 
} 

/** 
* Called when authentication is needed, but it's not sent 
*/ 
public function start(Request $request, AuthenticationException $authException = null) 
{ 
    $data = array(
     // you might translate this message 
     'message' => 'Authentication Required' 
    ); 

    return new JsonResponse($data, Response::HTTP_UNAUTHORIZED); 
} 

public function supportsRememberMe() 
{ 
    return false; 
} 
} 

定製監聽

class CustomAuthListener extends UsernamePasswordFormAuthenticationListener 
{ 
    private $csrfTokenManager; 
    private $tokenStorage; 

public function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, HttpUtils $httpUtils, $providerKey, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, array $options = array(), LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, CsrfTokenManagerInterface $csrfTokenManager = null) 
{ 
    parent::__construct($tokenStorage, $authenticationManager, $sessionStrategy, $httpUtils, $providerKey, $successHandler, $failureHandler, array_merge(array(
     'username_parameter' => '_username', 
     'password_parameter' => '_password', 
     'csrf_parameter' => '_csrf_token', 
     'csrf_token_id' => 'authenticate', 
     'post_only' => true, 
    ), $options), $logger, $dispatcher); 

    $this->csrfTokenManager = $csrfTokenManager; 
    $this->tokenStorage = $tokenStorage; 
} 

/** 
* {@inheritdoc} 
*/ 
protected function attemptAuthentication(Request $request) 
{ 
    if ($user = $this->tokenStorage->getToken() !== null) { 
     $user = $this->tokenStorage->getToken()->getUser(); 
     $username = $user->getUsername(); 

     if ($this->options['post_only']) { 
      $password = ParameterBagUtils::getParameterBagValue($request->request, $this->options['password_parameter']); 
     } else { 
      $password = ParameterBagUtils::getRequestParameterValue($request, $this->options['password_parameter']); 
     } 

     if (strlen($username) > Security::MAX_USERNAME_LENGTH) { 
      throw new BadCredentialsException('Invalid username.'); 
     } 

     $request->getSession()->set(Security::LAST_USERNAME, $username); 

     return $this->authenticationManager->authenticate(new UsernamePasswordToken($username, $password, $this->providerKey)); 
    } else { 
     return null; 
    } 
} 
} 

Listener服務

<service id="security.authentication.listener.form" class="Your\Path\To\CustomAuthListener" parent="security.authentication.listener.abstract" abstract="true" /> 
相關問題