[Google+ Portable SDK .NET] Obtener código de autorización (II)

Google + es compatible con el protocolo OAUTH2, el cual comienza obteniendo el Client ID y el Client Secret, después solicitaremos el “authorization code“, el cual será utilizado para obtener el token de acceso (parte 3). El flujo oAuth2 lo podemos ver en la siguiente imagen

flujo oath2

Vamos a implementar una librería portable para Windows Store App, Windows Phone 8 y aplicaciones de escritorio (concretamente WPF), la cual incluirá las referencias

– Microsoft Http Client 2.2.13: necesaria para realizar las peticiones HTTP al API HTTP de Google plus.

– Newtonsoft.JSON 5.06: necesaria para convertir las respuestas de Google plus (formato JSON) a un objeto NET.

ambas accesibles vía NuGet.

Antes de nada, vamos a recordar la hoja de ruta para esta serie de artículos

1. Crear aplicación Google +

2. Obtener código de autorización (actual)

3. Obtener Token de acceso

4. Obtener información del perfil.

5. Amigos en los círculos

6. Buscar Amigos

7. Obtener las publicaciones del muro

Una vez que tenemos el Client ID, Client Secret y Redirec URI (estos datos se pueden consultar en el Access Pane de nuestra aplicación Google Plus), el siguiente paso es hacer una petición GET a la dirección

https://accounts.google.com/o/oauth2/auth

en la cual hay que incluir los siguientes parámetros:

– client_id: este valor se obtiene al crear una aplicación google +.

– redirect_uri: si nuestra app es autorizada por el usuario final de google +, este valor determina donde será enviada la respuesta. En nuestro caso los posibles valores son:

1. http://localhost: el proceso de autorización redirige el navegador a http://localhost, incluyendo en la query string el código de autorización. Este será el proceso que usaremos en nuestro SDK.

2. urn:ietf:wg:oauth:2.0:oob. el código de autorización es mostrado en el navegador y es el propio usuario el que debe copiar manualmente el código de autorización y pegarlo en nuestra aplicación.

– response_type: su valor debe ser el literal “code“, para indicar que queremos solicitar un código de autorización.

– state: Es una cadena aleatoria que será usada para prevenir ataques del tipo CSRF (Cross-Site Request Forgery). Por simplicidad, hemos usado el método GenerarState , pero este método genera un valor demasiado simple, por este motivo, en un entorno de producción es necesario usar un generador de datos aleatorios más seguro.

        public string GenerarState()
        {
            try
            {
                return new Random().Next(11111, int.MaxValue).ToString("X2");
            }
            catch
            {
                throw;
            }
        }

– login_hint: este parámetro puede contener el email del usuario al que se le va a pedir autorización, con lo que evitaremos que el usuario tenga que escribirlo. Su valor es opcional.

scope: determina los permisos que nuestra app necesita sobre la cuenta google + del usuario final. Los posibles valores son:

https://www.googleapis.com/auth/plus.login Te permite identificar el usuario autentificado e identificar el intervalo de edad y el idioma preferido además de sus datos del perfil públicos. Para aplicaciones web y móviles que usan el botón de Inicio de sesión con Google+, este intervalo está incluido de manera implícita.El intervalo puede usarse para obtener una lista de las personas de los círculos para la que el usuario haya otorgado acceso a tu aplicación. También puedes solicitar escribir actividades en la aplicación para Google en nombre del usuario.No deberías solicitar userinfo.profile o plus.me en combinación con este intervalo ya que están incluidas de manera implícita y crearía un diálogo de permisos que podría confundir a tu usuario.
https://www.googleapis.com/auth/plus.me Te permite identificar quién es el usuario autentificado. En particular, en cualquier llamada al API puedes reemplazar la identificación del usuario de Google+ con meNo necesitas este intervalo si utilizas plus.login.
https://www.googleapis.com/auth/userinfo.email Te permite ver la dirección de correo electrónico del usuario. No obstante, el API de Google+ no devolverá direcciones de correo electrónico. Deberías enviar tu token de acceso al objetivo tokenInfo, y te devolverá la dirección de correo electrónico del usuario junto con el resto de información de validación.

Si se indica más de uno, estos deben separarse por un espacio en blanco (%20).

La construcción de la url completa se ha incluido en el método “ObtenerUrlAutorizacion” de la clase “smpGooglePlusApi“.

        public string ObtenerUrlAutorizacion(string appKey, string permisos = "https://www.googleapis.com/auth/plus.login https://www.googleapis.com/auth/userinfo.email", string emailUsuario = "", string callback = Declaraciones.URL_CALLBACK_WEBSERVER_LOCAL)
        {
            if (string.IsNullOrEmpty(appKey))
                throw new ArgumentException("appKey");
            if (string.IsNullOrEmpty(appKey))
                throw new ArgumentException("appKey");

            StringBuilder urlOAuth2 = new StringBuilder();
            urlOAuth2.Append(Declaraciones.URL_OAUTH2_AUTHORIZATION);
            //urlOAuth2.AppendFormat("?scope={0}", "https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile");
            if (!string.IsNullOrEmpty(permisos))
                urlOAuth2.AppendFormat("?scope={0}", permisos.UrlEncode());

            urlOAuth2.AppendFormat("&client_id={0}", appKey);

            urlOAuth2.AppendFormat("&redirect_uri={0}", callback);
            urlOAuth2.Append("&response_type=code");

            //este valor sera retornado de vuelta
            ComprobacionState = GenerarState();
            urlOAuth2.AppendFormat("&state={0}", ComprobacionState);

            //si sabemos el email del usuario que va a autorizar, lo podemos indicar en el parametro login_hint
            if (!string.IsNullOrEmpty(emailUsuario))
                urlOAuth2.AppendFormat("&login_hint={0}", emailUsuario);

            return urlOAuth2.ToString();
        }

Un ejemplo de petición seria:

https://accounts.google.com/o/oauth2/auth?scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fplus.login%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email&client_id=99999999999apps.googleusercontent.com&redirect_uri=http://localhost&response_type=code&state=D59565

Si copiamos esta url (sustituyendo en client id por uno real) y la pegamos en el navegador, el resultado es

google_plus_parte2_autorizacion

donde como se puede ver, la plataforma Google Plus solicita autorización al usuario final detallando los permisos que nuestra app necesita. Si el usuario hace clic en “Aceptar“, el navegador es redirigido a

http://localhost?code=<CODIGO AUTORIZACION>&state=D59565

ahora debemos comprobar que el valor del parámetro “state” coincida con el utilizado el crear la url de autorización. En caso afirmativo, el valor del parámetro “code“, representa el código de autorización.

Si en lugar de usar http://localhost, usamos urn:ietf:wg:oauth:2.0:oob, al completar la autorización se muestra una página con el código de autorización.

google_plus_parte2_autorizacion_win

En nuestro código SDK, no es necesario copiar la url y pegarla en el navegador, ya que en el proyecto de cada plataforma se ha incluido una pagina/ventana, la cual alberga un control del tipo WebBrowser. Por ejemplo, en el caso de la implementación para WPF:

<Window x:Class="DemoWPF.Navegador"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Navegador" Height="700" Width="900" Loaded="Window_Loaded">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
        </Grid.RowDefinitions>
        <TextBox Name="txtDireccion" Grid.Row="0" IsReadOnly="True"></TextBox>
        <WebBrowser Name="NavegadorWeb" Grid.Row="1" Navigating="NavegadorWeb_Navigating" Navigated="NavegadorWeb_Navigated"></WebBrowser>
    </Grid>
</Window>

mientras que el code-behind asociado es

    public partial class Navegador : Window
    {
        public string UrlAutoriacion { get; set; }
        public string CallBack { get; set; }

        public string Token { get; set; }
        public string State { get; set; }
        public Navegador()
        {
            InitializeComponent();
        }

        private void NavegadorWeb_Navigating(object sender, System.Windows.Navigation.NavigatingCancelEventArgs e)
        {
            txtDireccion.Text = e.Uri.ToString();
        }

        private void NavegadorWeb_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e)
        {
            if (NavegadorWeb.Source.ToString().StartsWith(CallBack))
            {
                string queryString = NavegadorWeb.Source.Query;
                Token = UtilidadesGenerales.ObtenerParametrosQueryString("code", queryString);
                State = UtilidadesGenerales.ObtenerParametrosQueryString("state", queryString);
                this.DialogResult = true;
                this.Close();
            }
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            this.NavegadorWeb.Navigate(this.UrlAutoriacion);
        }
    }

El evento “Navigated” es la parte principal, ya que comprueba si la url comienza por el valor de “redirect_uri“, y en caso afirmativo procesa la query string para obtener el valor de los parámetros “code” y “state“.

En la siguiente imagen se puede ver el aspecto del proyecto de ejemplo para windows phone 8.

google_plus_parte2_demophone

Una vez obtenido el código de autorización, podemos pasar a la siguiente entrega, en la cual obtendremos el token de acceso.

En el siguiente enlace se puede obtener información más detallada sobre el proceso oAuth 2.0 (para aplicaciones instaladas).

Como siempre, aquí tenéis el código de ejemplo. (WPF, W8, WP8)