API de Google+: ¿Cómo puedo usar RefreshTokens para evitar solicitar acceso cada vez que se inicia mi aplicación?


Estoy tratando de usar la API de Google+ para acceder a la información del usuario autenticado. He copiado algún código de una de las muestras, que funciona bien (a continuación), sin embargo, estoy teniendo problemas para que funcione de una manera que pueda reutilizar el token a través de lanzamientos de aplicaciones.

Intenté capturar la propiedad "refreshToken" y usar provider.RefreshToken() (entre otras cosas) y siempre obtengo una respuesta 400 Bad Request.

¿Alguien sabe cómo hacer que esto funcione, o sabe dónde puedo encontrar algunas muestras? El Código de Google site no parece cubrir esto : - (

class Program
{
    private const string Scope = "https://www.googleapis.com/auth/plus.me";

    static void Main(string[] args)
    {
        var provider = new NativeApplicationClient(GoogleAuthenticationServer.Description);
        provider.ClientIdentifier = "BLAH";
        provider.ClientSecret = "BLAH";
        var auth = new OAuth2Authenticator<NativeApplicationClient>(provider, GetAuthentication);

        var plus = new PlusService(auth);
        plus.Key = "BLAH";
        var me = plus.People.Get("me").Fetch();
        Console.WriteLine(me.DisplayName);
    }

    private static IAuthorizationState GetAuthentication(NativeApplicationClient arg)
    {
        // Get the auth URL:
        IAuthorizationState state = new AuthorizationState(new[] { Scope });
        state.Callback = new Uri(NativeApplicationClient.OutOfBandCallbackUrl);
        Uri authUri = arg.RequestUserAuthorization(state);

        // Request authorization from the user (by opening a browser window):
        Process.Start(authUri.ToString());
        Console.Write("  Authorization Code: ");
        string authCode = Console.ReadLine();
        Console.WriteLine();

        // Retrieve the access token by using the authorization code:
        return arg.ProcessUserAuthorization(authCode, state);
    }
}
Author: Danny Tuppeny, 2011-09-17

5 answers

Aquí hay un ejemplo. Asegúrese de agregar una configuración de cadena llamada refreshToken y sistema de referencia.Seguridad o encontrar otra manera de almacenar de forma segura el token de actualización.

    private static byte[] aditionalEntropy = { 1, 2, 3, 4, 5 };

    private static IAuthorizationState GetAuthorization(NativeApplicationClient arg)
    {
        // Get the auth URL:
        IAuthorizationState state = new AuthorizationState(new[] { PlusService.Scopes.PlusMe.GetStringValue() });
        state.Callback = new Uri(NativeApplicationClient.OutOfBandCallbackUrl);

        string refreshToken = LoadRefreshToken();
        if (!String.IsNullOrWhiteSpace(refreshToken))
        {
            state.RefreshToken = refreshToken;

            if (arg.RefreshToken(state))
                return state;
        }

        Uri authUri = arg.RequestUserAuthorization(state);

        // Request authorization from the user (by opening a browser window):
        Process.Start(authUri.ToString());
        Console.Write("  Authorization Code: ");
        string authCode = Console.ReadLine();
        Console.WriteLine();

        // Retrieve the access token by using the authorization code:
        var result = arg.ProcessUserAuthorization(authCode, state);

        StoreRefreshToken(state);
        return result;
    }

    private static string LoadRefreshToken()
    {
        return Encoding.Unicode.GetString(ProtectedData.Unprotect(Convert.FromBase64String(Properties.Settings.Default.RefreshToken), aditionalEntropy, DataProtectionScope.CurrentUser));
    }

    private static void StoreRefreshToken(IAuthorizationState state)
    {
        Properties.Settings.Default.RefreshToken = Convert.ToBase64String(ProtectedData.Protect(Encoding.Unicode.GetBytes(state.RefreshToken), aditionalEntropy, DataProtectionScope.CurrentUser));
        Properties.Settings.Default.Save();
    }
 20
Author: Lars Truijens,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-20 17:56:51

La idea general es la siguiente:

  1. Redirige al usuario al punto final de autorización de Google.

  2. Usted obtiene un código de autorización de corta duración.

  3. El código de autorización se intercambia inmediatamente por un Token de acceso de larga duración mediante el punto final de Token de Google. El Token de acceso viene con una fecha de caducidad y un Token de actualización.

  4. Realiza solicitudes a la API de Google mediante el Token de acceso.

Puede reutilizar el Acceda al token para tantas solicitudes como desee hasta que caduque. A continuación, puede utilizar el Token de actualización para solicitar un nuevo Token de acceso (que viene con una nueva fecha de caducidad y un nuevo Token de actualización).

Véase también:

 11
Author: dtb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-17 13:53:09

También tuve problemas para hacer que la autenticación "offline" funcionara (es decir, para adquirir la autenticación con un token de actualización), y obtuve HTTP-response 400 Bad request con un código similar al código de la OP. Sin embargo, Lo conseguí para trabajar con la línea client.ClientCredentialApplicator = ClientCredentialApplicator.PostParameter(this.clientSecret); en el método Authenticate. Esto es esencial para obtener un código de trabajo think Creo que esta línea obliga al ClientSecret a ser enviado como un POST-parámetro al servidor (en lugar de como un HTTP Basic Auth-parámetro).

Esta solución asume que ya tienes un ID de cliente, un secreto de cliente y un token de actualización. Tenga en cuenta que no es necesario introducir un token de acceso en el código. (Un código de acceso de corta duración se adquiere "bajo el capó" del servidor de Google al enviar el token de actualización de larga duración con la línea client.RefreshAuthorization(state);. Este token de acceso se almacena como parte de la variable auth, desde donde se usa para autorizar las llamadas a la API "under the hood".)

Un ejemplo de código que funciona para mí con Google API v3 para acceder a mi Calendario de Google:

class SomeClass
{

    private string clientID         = "XXXXXXXXX.apps.googleusercontent.com";
    private string clientSecret     = "MY_CLIENT_SECRET";
    private string refreshToken     = "MY_REFRESH_TOKEN";
    private string primaryCal       = "MY_GMAIL_ADDRESS";

    private void button2_Click_1(object sender, EventArgs e)
    {
        try
        {
            NativeApplicationClient client = new NativeApplicationClient(GoogleAuthenticationServer.Description, this.clientID, this.clientSecret);
            OAuth2Authenticator<NativeApplicationClient> auth = new OAuth2Authenticator<NativeApplicationClient>(client, Authenticate);

            // Authenticated and ready for API calls...

            // EITHER Calendar API calls (tested):
            CalendarService cal = new CalendarService(auth);
            EventsResource.ListRequest listrequest = cal.Events.List(this.primaryCal);
            Google.Apis.Calendar.v3.Data.Events events = listrequest.Fetch();
            // iterate the events and show them here.

            // OR Plus API calls (not tested) - copied from OP's code:
            var plus = new PlusService(auth);
            plus.Key = "BLAH";  // don't know what this line does.
            var me = plus.People.Get("me").Fetch();
            Console.WriteLine(me.DisplayName);

            // OR some other API calls...
        }
        catch (Exception ex)
        {
            Console.WriteLine("Error while communicating with Google servers. Try again(?). The error was:\r\n" + ex.Message + "\r\n\r\nInner exception:\r\n" + ex.InnerException.Message);
        }
    }

    private IAuthorizationState Authenticate(NativeApplicationClient client)
    {
        IAuthorizationState state = new AuthorizationState(new string[] { }) { RefreshToken = this.refreshToken };

        // IMPORTANT - does not work without:
        client.ClientCredentialApplicator = ClientCredentialApplicator.PostParameter(this.clientSecret);

        client.RefreshAuthorization(state);
        return state;
    }
}
 3
Author: poplitea,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-08-27 12:00:07

La especificación OAuth 2.0 aún no está terminada, y hay un puñado de implementaciones de especificaciones en los diversos clientes y servicios que causan que aparezcan estos errores. Lo más probable es que esté haciendo todo bien, pero la versión DotNetOpenAuth que está utilizando implementa un borrador diferente de OAuth 2.0 que Google está implementando actualmente. Ninguna de las partes es "correcta", ya que la especificación aún no está finalizada, pero hace que la compatibilidad sea una pesadilla.

Puede comprobar que la versión DotNetOpenAuth que está utilizando es la última (en caso de que ayude, que podría), pero en última instancia, es posible que deba sentarse hasta que las especificaciones estén finalizadas y todos las implementen correctamente, o leer los documentos de Google usted mismo (que presumiblemente describen su versión de OAuth 2.0) e implementar una que se dirija específicamente a su versión borrador.

 2
Author: Andrew Arnott,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-18 21:26:52

Recomendaría mirar el proyecto" SampleHelper"en la solución Samples de la API de cliente de Google. NET:

Este archivo muestra cómo usar los Datos Protegidos de Windows para almacenar un token de actualización, y también muestra cómo usar un Servidor de Bucle local y diferentes técnicas para capturar el código de Acceso en lugar de que el usuario lo ingrese manualmente.

Una de las muestras de la biblioteca que usa esto método de autorización se puede encontrar a continuación:

 2
Author: Matthias Linder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-21 08:34:35