2012-01-22 32 views
8

有人可以解釋一下如何在控制器中手動創建一個記住我的cookie?創建一個symfony2手動記住我的cookie(FOSUserBundle)

我希望用戶在按下「註冊」 按鈕後保持登錄狀態,而不必在之後使用憑據登錄。

我試着手動創建一個cookie,但我猜測cookie的 值不正確,因此「記住我」功能 不起作用。 設置了正確名稱的cookie。我檢查過了。

使用正常的 登錄過程和用戶​​的憑據時,記住我的功能按預期工作。

security.yml security.yml記得我

security: 
    firewalls: 
     main: 
      remember_me: 
       lifetime: 86400 
       domain: ~ 
       path: /
       key:  myKey 

這是我現在有,即使cookie設置,這是行不通的。

$um = $this->get('fos_user.user_manager'); 
$member = $um->createUser(); 

… Form stuff with bindRequest etc. 

$um->updatePassword($member); 
$um->updateUser($member); 

$providerKey = $this->container->getParameter('fos_user.firewall_name'); 
$securityKey = 'myKey'; 

$token = new RememberMeToken($member, $providerKey, $securityKey, 
$member->getRoles()); 
$this->container->get('security.context')->setToken($token); 

$redirectResponse = new RedirectResponse($url); 
$redirectResponse->headers->setCookie(
    new \Symfony\Component\HttpFoundation\Cookie(
     'REMEMBERME', 
     base64_encode(implode(':', array($member->getUsername(), 
$member->getPassword()))), 
     time() + 60*60*24 
    ) 
); 
return $redirectResponse; 

更新:

我也試着與反射 對PersistentTokenBasedRememberMeServices類的工作,但它不工作。一個cookie被設置,但我使用的Symfony V2.0.5和FOSUserBundle它不工作

$token = $this->container->get('security.context')->getToken(); 

$providerKey = $this->container->getParameter('fos_user.firewall_name'); 
$securityKey = 'myKey'; 

$persistenService = new 
PersistentTokenBasedRememberMeServices(array($um), $providerKey, 
$securityKey, array('path' => '/', 'name' => 'REMEMBERME', 'domain' => 
null, 'secure' => false, 'httponly' => true, 
'lifetime' => 86400)); 
$persistenService->setTokenProvider(new InMemoryTokenProvider()); 

$method = new \ReflectionMethod('Symfony\Component\Security\Http\RememberMe\PersistentTokenBasedRememberMeServices', 
'onLoginSuccess'); 
$method->setAccessible(true); 
$method->invoke($persistenService, $request, $redirectResponse, $token); 

1.0

更新2:

我已經嘗試了3次的方式。與上面相同,但沒有反映:

$token = $this->container->get('security.context')->getToken(); 

$providerKey = $this->container->getParameter('fos_user.firewall_name'); 
$securityKey = 'myKey'; 

$persistenService = new PersistentTokenBasedRememberMeServices(array($um), $providerKey, $securityKey, array('path' => '/', 'name' => 'REMEMBERME', 'domain' => null, 'secure' => false, 'httponly' => true, 'lifetime' => 31536000, 'always_remember_me' => true, 'remember_me_parameter' => '_remember_me')); 
$persistenService->setTokenProvider(new InMemoryTokenProvider()); 

$persistenService->loginSuccess($request, $redirectResponse, $token); 

回答

10

如果直接設置了rememberMe cookie,您必須使用以下格式:

base64_encode(<classname>:base64_encode(<username>):<expiry-timestamp>:<hash>) 

其中散列將是:

sha256(<classname> . <username> . <expiry-timestamp> . <password> . <key>) 

密鑰是您在remember_me部分中輸入到安全性(.xml/.yml)中的密鑰。

這是從processAutoLoginCookie()方法在的Symfony /組件/安全/ HTTP /與rememberMe/TokenBasedRememberMeService.php文件中獲取。

這一切都是由generateCookieValue()方法在同一個類中完成的。

但是,我不會建議直接使用這種方式來執行此操作,但請嘗試查看是否可以調用TokenBasedRememberMeService::onLoginSuccess()方法,該方法會爲您設置此Cookie以使代碼更加健壯和便攜。

12

這是我做到的。我沒有使用FOSUserBundle,我使用的是Doctrine Entity User Provider,但它應該微不足道,以適應您的需求。這裏是一個通用的解決方案:

// after registration and persisting the user object to DB, I'm logging the user in automatically 
$token = new UsernamePasswordToken($user, null, 'main', $user->getRoles()); 

// but you can also get the token directly, if you're user is already logged in 
$token = $this->container->get('security.context')->getToken(); 

// write cookie for persistent session storing 
$providerKey = 'main'; // defined in security.yml 
$securityKey = 'MySecret'; // defined in security.yml 

$userProvider = new EntityUserProvider($this->getDoctrine()->getEntityManager(), 'MyCompany\MyBundle\Entity\User', 'username'); 

$rememberMeService = new TokenBasedRememberMeServices(array($userProvider), $securityKey, $providerKey, array(
       'path' => '/', 
       'name' => 'MyRememberMeCookie', 
       'domain' => null, 
       'secure' => false, 
       'httponly' => true, 
       'lifetime' => 1209600, // 14 days 
       'always_remember_me' => true, 
       'remember_me_parameter' => '_remember_me') 
      ); 

$response = new Response(); 
$rememberMeService->loginSuccess($request, $response, $token); 

// further modify the response 
// ........ 

return $response; 

只要記住你必須設置到true(就像我在上面的代碼中所做的那樣)或在$ _ POST參數莫名其妙地擁有它,否則方法的AbstractRememberMeServicesisRememberMeRequested將返回false和該cookie不會被存儲。

你是相當接近,雖然正確的解決方案:)你做了什麼錯誤(在第三嘗試)是你已經改變了這裏的參數的順序:

$persistenService = new PersistentTokenBasedRememberMeServices(array($um), $providerKey, $securityKey, array('path' => '/', 'name' => 'REMEMBERME', 'domain' => null, 'secure' => false, 'httponly' => true, 'lifetime' => 31536000, 'always_remember_me' => true, 'remember_me_parameter' => '_remember_me')); 

__construct()看看AbstractRememberMeServices.php。你應該通過一個$securityKey作爲第二個參數和$providerKey作爲第三個參數,而不是相反的方式,就像你犯的錯誤;)

我還不知道,是如何從security.yml中直接獲取參數控制器不要複製它。通過使用$this->container->getParameter(),我可以將參數存儲在config.yml中的parameters密鑰下,但不能將配置樹中位置較高的參數存儲在配置樹中。對此有何想法?

+1

對於security.yml越來越餅乾參數和避免重複的原始程序,你應該把它們放在parameters.yml和安全.yml使用%your_parameter_name%調用它們。它們現在可用於安全性和參數 – guillaumepotier

+3

+1爲此使用Symfony2安全類。請記住,remember-me Cookie的默認Cookie名稱是「REMEMBERME」。只有當您使用相同的cookie名稱作爲防火牆時,您纔會通過手動設置cookie進行身份驗證,安全監聽程序將會識別這些cookie。 – flu

+1

傳遞給Symfony \ Bridge \ Doctrine \ Security \ User \ EntityUserProvider :: __ construct()的參數1必須實現接口Doctrine \ Common \ Persistence \ ManagerRegistry,Doctrine \ ORM \ EntityManager的實例,因爲我得到了D: –

0

對我來說,最簡單的方法是延長BaseTokenBasedRememberMeServices並讓它處理

namespace AppBundke\Security\Http; 
use Symfony\Component\HttpFoundation\Cookie; 
use Symfony\Component\Security\Http\RememberMe\TokenBasedRememberMeServices as BaseTokenBasedRememberMeServices; 


class TokenBasedRememberMeServices extends BaseTokenBasedRememberMeServices 
{ 
    protected $options_new = array('name' => 'REMEMBERME', 'domain' => null, 'path' => '/'); 

    public function __construct($userProvider, $secret, $providerKey, array $options = array(), LoggerInterface $logger = null) 
    { 
      return parent::__construct(array($userProvider), $secret, $providerKey, array_merge($this->options_new, $options)); 
    } 

    public function generateCookie($user, $username, $expires, $password) 
    { 
     $cookie = new Cookie(
      $this->options['name'], 
      parent::generateCookieValue(get_class($user), $username, $expires, $password), 
      $expires, 
      $this->options['path'], 
      $this->options['domain'], 
      $this->options['secure'], 
      $this->options['httponly'] 
     ); 
    return $cookie; 
    } 
} 

和控制器;

$user = $this->getUser(); 
$providerKey = $this->getParameter('fos_user.firewall_name'); 
$secret = $this->getParameter('secret'); 
$cookie_life_time = $this->getParameter('cookie_life_time'); 

$remember_me_service = new TokenBasedRememberMeServices($user, $secret, $providerKey); 
$remember_me_cookie = $remember_me_service->generateCookie($user, $user->getUsername(),(time() + $cookie_life_time), $user->getPassword()); 

則響應集合cookie來$ remember_me_cookie

我希望它的作品與大家2.

0

我有同樣的問題,當我試圖通過令牌的連接後設置了rememberMe的cookie的用戶,使用Guard Authentication

在這種情況下,我沒有Response對象可以使用$ response-> headers-> setCookie()並需要使用setcookie()。 而在這種情況下,創建RedirectResponse並不合適。

這需要重構,但我在後,我根據我的服務

$expires = time() + 2628000; 
$hash = hash_hmac(
    'sha256', 
    get_class($user).$user->getUsername().$expires.$user->getPassword(), 'secret in parameters.yml' 
); 
$value = base64_encode(implode(':', [get_class($user), base64_encode($user->getUsername()), $expires, $hash])); 
setcookie(
    'REMEMBERME', 
    $value, 
    $expires, 
    '/', 
    'host', 
    'ssl boolean', 
    true 
);