Symfony2: Impersonating – Hacerse pasar por otro usuario

Esto es una funcionalidad que trae Symfony2 por defecto y es realmente útil. Lo que nos permite impersonating es poder hacerte pasar por otro usuario sin tener que loguearte y desloguearte, esto es muy útil cuando un usuario descubre un fallo y no lo puedes reproducir con tu usuario.

Para activar esta opción se hace a través de la configuración de seguridad:

Esta es la configuración por defecto, lo que significa que para poder cambiarte de usuario tienes que tener el rol ROLE_ALLOWED_TO_SWITCH y acceder a la url:

Si entramos a esa url y tenemos el rol que hemos comentado, el usuario autenticado cambiaría a thomas. Para volver al usuario original hay que hacerlo con el valor _exit:

Cuando cambiamos de usuario, automáticamente se nos añade el rol ROLE_PREVIOUS_ADMIN que nos permitirá entre otras cosas en la vista mostrar un enlace para volver al usuario anterior:

Si queremos cambiar el rol necesario para cambiar de usuario o el nombre del parámetro podemos hacerlo a través de la configuración:

Todo esto se puede leer en la documentación.

Ejemplo

Para verlo en funcionamiento nosotros añadiremos la siguiente configuración:

Con esto indicamos que activamos la funcionalidad de cambiar de usuario, que sólo está disponible para los usuarios con rol ROLE_SMTC y que el parámetro es _change_to. También hemos creado una ruta llamada logout en el routing.yml que indicamos en el security.yml que será la ruta para que el usuario pueda desloguearse. En la vista hemos usado la nueva función de Symfony2.1 logout_path que recibe como parámetro el firewall y devuelve la ruta para desloguearse:

Vamos a usar los usuarios en memoria por lo que disponemos de los siguientes:

En el controller lo único que haremos será que si no estamos logueados, lo haremos como smtc que es quien tiene el rol ROLE_SMTC:

Hemos refactorizado el método loginAs que habíamos creado en el post anterior para que sólo reciba el username y que obtenga el usuario de los que hay en memoria. La parte interesante de esto es el servicio que hemos creado en security.xml:

No es nada más que un alias a otro servicio ¿por qué? Porque si un servicio está declarado como privado (public=”false”) no se puede acceder directamente a él a través del contenedor ($container->get(‘service.id’)), si queremos hacerlo hay que declararse un alias como es este caso. De todas formas, lo mejor hubiera sido crear un servicio al que le inyectamos el security.context y el in_memory provider, así lo podemos reutilizar y testear más fácilmente y no necesitamos el alias, seguramente lo cambiaremos, pero de momento y para ver el ejemplo de alias lo dejaremos así.

Para finalizar, si has cambiado de usuario e intentas cambiar a otro se lanzará una excepción (LogicException) indicando que You are already switched to “user” user. (siendo “user” el usuario por el que nos estamos haciendo pasar) por lo que hay que hacer una llamada con el valor _exit primero o si intentas cambiar de usuario con uno que no tiene el rol necesario se lanzará una AccessDeniedHttpException.

Ver Demo

Feliz año nuevo!