2013-01-14 100 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; 
    } 
}