2012-01-22 24 views
8

¿Podría alguien explicar cómo puede crear manualmente una cookie de recordarme en un controlador?Crear un symfony2 recordarme cookie manualmente (FOSUserBundle)

Quiero que los usuarios sigan conectados después de presionar el botón "registrar" , sin tener que iniciar sesión con sus credenciales después.

He intentado crear una cookie manualmente, pero supongo que el valor de cookie es incorrecto, y por eso la funcionalidad "recordarme" no funciona. Se establece una cookie con el nombre correcto. Lo he comprobado.

La función Recordarme funciona de la manera esperada cuando se utiliza el procedimiento normal de inicio de sesión con las credenciales del usuario.

security.yml me

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

security.yml recuerda que esto es lo que tengo ahora, a pesar de que la cookie se establece, no funciona.

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

Actualización:

También he intentado trabajar con la clase PersistentTokenBasedRememberMeServices con la reflexión, pero no funciona. una galleta consigue el sistema pero que no está funcionando

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

estoy usando Symfony v2.0.5 y FOSUserBundle 1.0

ACTUALIZACIÓN 2:

He intentado una tercera manera. Lo mismo que el anterior pero sin reflexión:

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

Respuesta

10

Si está configurando la cookie rememberme directamente, usted tiene que utilizar el siguiente formato:

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

donde el hash será:

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

la clave es la clave que ha ingresado en su seguridad (.xml/.yml) en la sección remember_me.

Esto está tomado de processAutoLoginCookie() método en el Symfony/Componente/Seguridad/HTTP/RememberMe/TokenBasedRememberMeService.php archivo.

Todo esto se realiza mediante el método generateCookieValue() en la misma clase.

Sin embargo, no recomendaría hacerlo de esta manera directamente, pero intente ver si puede llamar al método TokenBasedRememberMeService::onLoginSuccess(), que establece esta cookie para que el código sea más robusto y portátil.

12

Así es como lo hice. No estoy usando FOSUserBundle y estoy usando Doctrine Entity User Provider, pero debe ser trivial para ajustarse a sus necesidades.Aquí es una solución general:

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

Sólo recuerde que usted tiene que fijar a true (como lo hice en el código anterior) o lo tiene en sus $ _POST parámetros de alguna manera, de lo contrario método isRememberMeRequested de AbstractRememberMeServices volverá falsa y la cookie no será almacenada.

Usted eran bastante cerca de la solución correcta aunque :) lo que hizo mal (en la tercera tentativa) es que se ha cambiado el orden de los parámetros aquí:

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

Tome un vistazo a __construct() en AbstractRememberMeServices.php. Debería pasar un $securityKey como segundo argumento y $providerKey como tercer argumento, y no al revés, como lo hizo por error;)

Lo que aún no sé es cómo obtener los parámetros de security.yml directamente en el controlador para no duplicarlo. Al usar $this->container->getParameter() puedo obtener los parámetros almacenados bajo la clave parameters en config.yml, pero no los que se colocan más arriba en el árbol de configuración. Tiene alguna idea sobre esto?

+1

Para la obtención de parámetros de la cookie en security.yml y evitar duplicados, debe ponerlos en parameters.yml y en la seguridad .yml los llama con% your_parameter_name%. Ahora están disponibles en seguridad y en los parámetros – guillaumepotier

+3

+1 Para usar las clases de seguridad de Symfony2 para esto. Tenga en cuenta que el nombre predeterminado de las cookies para recordarme es 'REMEMBERME'. Solo si utiliza el mismo nombre de cookie que el servidor de seguridad que está autenticando en contra de su conjunto manual, la cookie será reconocida por el agente de escucha de seguridad. – flu

+1

Argumento 1 pasado a Symfony \ Bridge \ Doctrine \ Security \ User \ EntityUserProvider :: __ construct() debe implementar la interfaz Doctrine \ Common \ Persistence \ ManagerRegistry, instancia de Doctrine \ ORM \ EntityManager dado que obtuve D: –

0

Para mí la solución más fácil era extender una BaseTokenBasedRememberMeServices y se deja manejar

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

y en el controlador;

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

continuación de respuesta ajustado cookie a $ remember_me_cookie

espero sus trabajos con ustedes 2.

0

que tenía el mismo problema cuando traté de establecer cookies Rememberme un usuario después de una conexión por ficha, usando Guard Authentication.

En esta situación no tenía ningún objeto Response para poder usar $ response-> headers-> setCookie() y necesita usar setcookie(). Y en esta situación, crear un RedirectResponse no es apropiado.

Esto tiene que ser reprogramado pero publicar el procedimiento prima sobre la que basé mi servicio

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