API Google+: Как я могу использовать RefreshTokens, чтобы не запрашивать доступ при каждом запуске моего приложения? - PullRequest
23 голосов
/ 17 сентября 2011

Я пытаюсь использовать Google+ API для доступа к информации для аутентифицированного пользователя. Я скопировал некоторый код из одного из примеров, который работает нормально (ниже), однако у меня возникают проблемы с тем, чтобы заставить его работать таким образом, чтобы я мог повторно использовать токен при запуске приложения.

Я пытался захватить свойство "RefreshToken" и использовать provider.RefreshToken() (среди прочего) и всегда получал 400 Bad Request ответ.

Кто-нибудь знает, как заставить это работать, или знает, где я могу найти некоторые образцы? Сайт Google Code , кажется, не покрывает это: - (

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

Ответы [ 5 ]

20 голосов
/ 20 сентября 2011

Вот пример. Убедитесь, что вы добавили строковый параметр RefreshToken и ссылаетесь на System.Security или нашли другой способ безопасного хранения токена обновления.

    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();
    }
11 голосов
/ 17 сентября 2011

Общая идея заключается в следующем:

  1. Вы перенаправляете пользователя в конечную точку авторизации Google.

  2. Вы получаете недолговечную авторизациюКод.

  3. Вы немедленно меняете код авторизации на долгоживущий токен доступа, используя конечную точку токена Google.Токен доступа поставляется с датой истечения срока действия и токеном обновления.

  4. Вы делаете запросы к API Google с помощью токена доступа.

Вы можетеповторно использовать токен доступа для любого количества запросов, пока он не истечет.Затем вы можете использовать токен обновления, чтобы запросить новый токен доступа (который поставляется с новой датой истечения срока действия и новым токеном обновления).

См. Также:

3 голосов
/ 27 августа 2012

У меня также были проблемы с получением «автономной» аутентификации для работы (то есть получения аутентификации с помощью токена обновления), и я получил HTTP-ответ 400 Bad request с кодом, похожим на код OP. Тем не менее, Я получил его для работы со строкой client.ClientCredentialApplicator = ClientCredentialApplicator.PostParameter(this.clientSecret); в Authenticate -методе. необходимо для получения рабочего кода - я думаю, что эта строка заставляет clientSecret отправляться на сервер как POST-параметр (а не как HTTP-параметр Auth).

Это решение предполагает, что у вас уже есть идентификатор клиента, секрет клиента и токен обновления. Обратите внимание, что вам не нужно вводить токен доступа в коде. (Короткоживущий код доступа получен «под капотом» с сервера Google при отправке долгоживущего токена обновления со строкой client.RefreshAuthorization(state);. Этот токен доступа хранится как часть auth - переменная, откуда она используется для авторизации API-вызовов «под капотом».)

Пример кода, который работает для меня с Google API v3 для доступа к моему Календарю 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;
    }
}
2 голосов
/ 21 сентября 2011

Я бы порекомендовал посмотреть на проект "SampleHelper" в решении Samples клиентского API Google .NET:

Этот файл показывает, как использовать защищенные данные Windows для хранения токена обновления, а также показывает, как использовать локальный сервер Loopback Server и различные методы для захвата кода доступа вместо того, чтобы пользователь вводил его вручную.

Один из примеров в библиотеке, использующих этот метод авторизации, можно найти ниже:

2 голосов
/ 19 сентября 2011

Спецификация OAuth 2.0 еще не закончена, и существует несколько реализаций спецификаций для различных клиентов и служб, которые вызывают появление этих ошибок. Скорее всего, вы все делаете правильно, но версия DotNetOpenAuth, которую вы используете, реализует черновик OAuth 2.0, отличный от того, который сейчас используется в Google. Ни одна из частей не является «правильной», поскольку спецификация еще не доработана, но совместимость превращается в настоящий кошмар.

Вы можете проверить, что версия DotNetOpenAuth, которую вы используете, является самой последней (в случае, если это поможет, что может ), но в конечном счете вам, возможно, придется либо сидеть сложа руки, пока спецификации не будут завершены, и все реализует их правильно, либо самостоятельно прочитайте документы Google (которые, вероятно, описывают их версию OAuth 2.0) и внедрите ту, которая специально предназначена для их черновой версии.

...