2012-01-22 9 views
8

Czy ktoś mógłby wyjaśnić, w jaki sposób możesz ręcznie utworzyć plik cookie "zapamiętaj mnie" w kontrolerze?Utwórz plik cookie symfony2 pamiętaj mnie ręcznie (FOSUserBundle)

Chcę, aby użytkownicy pozostali zalogowani po naciśnięciu przycisku "zarejestruj się" pod numerem , bez konieczności późniejszego logowania za pomocą swoich danych uwierzytelniających.

Próbowałem ręcznie utworzyć plik cookie, ale domyślam się, że wartość cookie jest niepoprawna, dlatego funkcja "zapamiętaj mnie" nie działa. Zostanie ustawiony plik cookie o poprawnej nazwie. Sprawdziłem to.

Funkcja zapamiętaj mnie działa zgodnie z oczekiwaniami podczas korzystania z normalnej procedury logowania przy użyciu poświadczeń użytkownika.

security.yml security.yml zapamiętaj

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

To jest to, co mam teraz, mimo że plik cookie jest ustawiony, to nie działa.

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

Aktualizacja:

Próbowałem zostały również pracować z klasą PersistentTokenBasedRememberMeServices z refleksji, ale to nie działa. ciasteczko zostanie ustawiona, ale to nie działa

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

Używam Symfony v2.0.5 i FOSUserBundle 1,0

UPDATE 2:

Próbowałem 3rd drogę. Tak samo jak powyżej, ale bez refleksji:

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

Odpowiedz

10

Jeśli ustawienie cookie Twój na zawsze bezpośrednio, trzeba użyć następującego formatu:

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

gdzie hash będzie:

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

Klucz jest kluczem wprowadzonym w twoim zabezpieczeniu (.xml/.yml) w sekcji remember_me.

To jest wzięte z processAutoLoginCookie() metody w Symfony/Component/Bezpieczeństwo/HTTP/Twój na zawsze/TokenBasedRememberMeService.php plików.

Wszystko to odbywa się za pomocą metody generateCookieValue() w tej samej klasie.

Jednak nie polecam używania tego w ten sposób bezpośrednio, ale spróbuj sprawdzić, czy możesz zadzwonić pod metodę TokenBasedRememberMeService::onLoginSuccess(), która ustawia plik cookie, aby kod był bardziej wytrzymały i przenośny.

12

Oto jak to zrobiłem. Nie używam FOSUserBundle i korzystam z Provign Entity User Provider, ale powinno być trywialnie dostosować się do twoich potrzeb.Oto ogólne rozwiązanie:

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

Wystarczy pamiętać trzeba ustawić do true (tak jak ja w kodzie powyżej) lub mieć go w swoim parametry $ _POST jakoś inaczej metoda isRememberMeRequested z AbstractRememberMeServices zwróci false i plik cookie nie zostanie zapisany.

Byłaś całkiem blisko do prawidłowego rozwiązania chociaż :) Co zrobiłeś źle (w 3 próby) jest to, że zmieniłem kolejność parametrów tutaj:

$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')); 

przyjrzeć __construct() w AbstractRememberMeServices.php. Powinieneś przekazać $securityKey jako drugi argument, a nie odwrotnie, jak to zrobiłeś przez pomyłkę;)

Co jeszcze nie wiem, to jak uzyskać parametry z security.yml bezpośrednio w kontroler, aby go nie powielić. Korzystając z $this->container->getParameter(), mogę uzyskać parametry przechowywane pod kluczem parameters w pliku config.yml, ale nie te, które znajdują się wyżej w drzewie konfiguracji. Jakieś przemyślenia na ten temat?

+1

Dla uzyskania parametrów cookie w security.yml i uniknąć duplikatów, należy umieścić je w parameters.yml i bezpieczeństwa .yml wywołaj je za pomocą% twoja_nazwa_parametru%. Są teraz dostępne w zabezpieczeniach i parametrach – guillaumepotier

+3

+1 Do korzystania z klas bezpieczeństwa Symfony2. Należy pamiętać, że domyślną nazwą pliku cookie "Remember Me" jest "REMEMBERME". Tylko wtedy, gdy użyjesz tej samej nazwy pliku cookie, co firewall, którego autentykacja dotyczy Twojego ręcznego ustawienia ciasteczka, zostanie rozpoznany przez program nasłuchujący. – flu

+1

Argument 1 przekazany do Symfony \ Bridge \ Doctrine \ Security \ User \ EntityUserProvider :: __ construct() musi zaimplementować interfejs Doctrine \ Common \ Persistence \ ManagerRegistry, instancja Doctrine \ ORM \ EntityManager podana Mam to D: –

0

Dla mnie najprostszym rozwiązaniem było przedłużyć BaseTokenBasedRememberMeServices i niech sobie

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

i kontroler;

$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()); 

wówczas reakcja ustawić ciasteczko do $ remember_me_cookie

Mam nadzieję, że jego prace z wami 2.

0

miałem ten sam problem, gdy próbowałem ustawić Twój na zawsze ciasteczko Użytkownikowi po połączeniu przez token, przy użyciu Guard Authentication.

W tej sytuacji nie miałem obiektu Response, aby móc użyć $ response-> headers-> setCookie() i trzeba użyć setcookie(). I w tej sytuacji Utwórz RedirectResponse nie jest właściwe.

To musi być refactored ale pisać surowe proceduralny, na której oparłem usługę

$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 
); 
Powiązane problemy