lunes, 12 de marzo de 2012

Android + Symfony2: Autentificación

Hoy en día una tarea bastante común es validar las credenciales de un usuario remotamente. En mi caso necesito que una aplicación ejecutándose en Android se valide en el sistema principal que esta construido con Symfony2 y con FOSUserBundle como proveedor de usuarios.

Ya que FOSUB se encarga de la validación en el sitio web, lo ideal y mas lógico seria que también se encarga de la validación remota, evitando duplicar trabajo y cometer errores. En esencia es el mismo escenario que cuando el usuario quiere iniciar sesión desde un navegador tradicional. Pero con algunas diferencias, así que manos a la obra.

Symfony2
En nuestro proyecto de Symfony tenemos que definir un firewall para hacer accesible la autentificacion via HTTP:

security.yml
 api:  
  pattern: ^/api/.*  
  stateless: true  
  security: true  
  http_basic:  
    realm: "API"  

access_control:
  - { path: /api/, role: ROLE_USER }

Con estas lineas presentes en el firewall, cada vez que se quiera acceder una ruta del siguiente tipo <nuestro-domino>/api/ se generara una petición para iniciar sesión mediante HTTP.


routing.yml
 api_login:  
   pattern: /api/login  
   defaults: { _controller: AcmeUserBundle:Security:apiLogin }  


En el rounting es necesario indicar el controlador y la acción a realizar.


SecurityController
 public function apiLoginAction()  
 {  
   $response = new Response();  
   $response->setContent('<html><body>OK</body></html>');  
   $response->setStatusCode(200);  
   $response->headers->set('Content-Type', 'text/html');  
   
   return $response;  
 }  


Y finalmente en el controlador generamos la respuesta, es muy importante indicar el código html de la respuesta para poder saber en Android si el login fue correcto o no.



Android
En Android hay que implementar la siguiente funcion, creando un cliente HTML y dandole una peticion GET para acceder a la URL.

  1 public int login(String username, String password)
  2 { 
  3     HttpClient httpClient = new DefaultHttpClient();
  4      
  5     //construir peticion get 
  6     HttpGet httpGet = new HttpGet("url");
  7     httpGet.addHeader(BasicScheme.authenticate( 
  8             new UsernamePasswordCredentials(username,password), "UTF-8", false)); 
  9      
 10     //ejecutar get y recibir respuesta 
 11     HttpResponse response = null; 
 12     Boolean error = false; 
 13     try { 
 14         response = httpClient.execute(httpGet); 
 15     } catch (ClientProtocolException e) { 
 16         error = true; 
 17         e.printStackTrace(); 
 18     } catch (IOException e) { 
 19         error = true; 
 20         e.printStackTrace(); 
 21     } finally{ 
 22         //cerrar conexion htl y liberar recursos
 23         httpClient.getConnectionManager().shutdown(); 
 24     } 
 25      
 26     //devolver algun codigo (exito, fallo, error, etc) 
 27 }

Este es el caso mas básico de autentificación, ya que al ser HTTP Basic, el usuario y el password van en texto plano. Pero para la etapa de desarrollo y depuración es bastante útil.


Y con esto estaría todo funcionando. Mas adelante me tocara implementar un inicio de sesión para producción (así que tendrá que ser seguro), así que eso ya vendrá en otro post.