2013-01-14 98 views
7

我試圖在使用Symfony2訪問網站時實現單點登錄。以編程方式登錄並保持登錄狀態

認證本身似乎工作正常,但只適用於初始頁面。在下一頁加載的用戶不再登錄。

相關代碼:

$token = new UsernamePasswordToken($user, null, 'main', $user->getRoles()); 
$event = new InteractiveLoginEvent($request, $token); 

$this->get("event_dispatcher")->dispatch(SecurityEvents::INTERACTIVE_LOGIN, $event); 
$this->get("security.context")->setToken($token); 

return $this->redirect($this->generateUrl('sonata_user_profile_show')); 

第一頁(無需重定向):

Initial page - logged in

第二頁:

Second page - Not logged in anymore

+0

你在使用Symfony 2.1嗎?如果是這樣,請嘗試添加以下行: '$ session-> set('_ security_'。$ firewallName,serialize($ token)); $ session-> save();' – Squazic

+0

我有一個這樣的問題,我正在處理一個ASP.NET Web應用程序。我在瀏覽器中清除了緩存,然後又開始工作。希望對你來說也很簡單:) – Anonymous

+0

@Squazic是的,我正在使用Symfony 2.1。我添加了會話片段,但不幸的是,這沒有奏效。 –

回答

6

自定義登錄只需要以下代碼。

$token = new UsernamePasswordToken($user, null, 'main', $user->getRoles()); 
$this->get("security.context")->setToken($token); 

return $this->redirect($this->generateUrl('sonata_user_profile_show')); 

這是在安全上下文中設置UsernamePasswordToken。該令牌(以及用戶)將被序列化並放入會話中。在下一頁上,該令牌將從會話中反序列化,並且還將反序列化的用戶將被刷新。

FOSUserBundle中的用戶提供程序使用非序列化用戶的標識進行刷新。

此外,Doctrine2在某些情況下使用代理類作爲實體類而不是原始實體類。該代理類通過複雜的延遲加載複雜實現覆蓋實體的「getId()」函數。

這一起可能導致這樣的事實:當您將Doctrine2代理對象放入UserPasswordToken中時,序列化的,然後反序列化的代理對象的「getId()」將不會返回原始ID。當這種情況發生時,用戶不能刷新用戶,令牌將無效。

解決此問題的方法是創建一個自定義用戶提供程序,通過使用用戶名(或其他獨特屬性)進行刷新來覆蓋「refreshUser()」。

//... 
class UserProvider extends FOSUserProvider 
{ 
    /** 
    * {@inheritDoc} 
    */ 
    public function refreshUser(SecurityUserInterface $user) 
    { 
     if (!$user instanceof User) { 
      throw new UnsupportedUserException(sprintf('Expected an instance of User, but got "%s".', get_class($user))); 
     } 

     if (null === $reloadedUser = $this->userManager->findUserBy(array('username' => $user->getUsername()))) { 
      throw new UsernameNotFoundException(sprintf('User with username "%s" could not be reloaded.', $user->getUsername())); 
     } 

     return $reloadedUser; 
    } 
}