web-dev-qa-db-ja.com

Google+ API:アプリが起動するたびにアクセスを要求しないようにRefreshTokensを使用するにはどうすればよいですか?

Google+ APIを使用して、認証されたユーザーの情報にアクセスしようとしています。サンプルの1つからいくつかのコードをコピーしましたが、これは正常に機能します(以下)。ただし、アプリの起動間でトークンを再利用できるように機能させるのに問題があります。

「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);
    }
}
23
Danny Tuppeny

これが例です。必ず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();
    }
20
Lars Truijens

一般的な考え方は次のとおりです。

  1. ユーザーをGoogleの承認エンドポイントにリダイレクトします。

  2. 短期間の認証コードを取得します。

  3. Googleのトークンエンドポイントを使用して、認証コードを有効期間の長いアクセストークンとすぐに交換します。アクセストークンには、有効期限と更新トークンが付属しています。

  4. アクセストークンを使用してGoogleのAPIにリクエストを送信します。

アクセストークンは、有効期限が切れるまで、必要な数のリクエストに再利用できます。次に、更新トークンを使用して、新しいアクセストークン(新しい有効期限と新しい更新トークンが付属)をリクエストできます。

関連項目:

11
dtb

また、「オフライン」認証を機能させる(つまり、更新トークンを使用して認証を取得する)ことに問題があり、OPのコードと同様のコードでHTTP応答_400 Bad request_を取得しました。ただし、Authenticate-メソッドの行client.ClientCredentialApplicator = ClientCredentialApplicator.PostParameter(this.clientSecret);で機能するようになりました。これは必須動作するコードを取得するためです-この行は、clientSecretを(HTTP基本認証パラメーターとしてではなく)POSTパラメーターとしてサーバーに送信するように強制すると思います。

このソリューションは、クライアントID、クライアントシークレット、および更新トークンが既にあることを前提としています。コードにアクセストークンを入力する必要がないことに注意してください。 (短期間のアクセスコードは、client.RefreshAuthorization(state);という行で長期のリフレッシュトークンを送信するときに、Googleサーバーから「内部」で取得されます。このアクセス-トークンはauth-変数の一部として保存され、そこからAPIの承認に使用されます-「内部」の呼び出し。)

GoogleカレンダーにアクセスするためのGoogleAPI v3で機能するコード例:

_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
poplitea

Google.NETクライアントAPIのサンプルソリューションの「SampleHelper」プロジェクトを確認することをお勧めします。

このファイルは、Windows保護データを使用して更新トークンを保存する方法と、ユーザーが手動で入力する代わりにローカルループバックサーバーとさまざまな手法を使用してアクセスコードをキャプチャする方法の両方を示しています。

この認証方法を使用するライブラリのサンプルの1つは、以下にあります。

2
Matthias Linder

OAuth 2.0仕様はまだ完成しておらず、さまざまなクライアントやサービス全体に仕様の実装が散在しているため、これらのエラーが表示されます。ほとんどの場合、すべてを正しく行っています。ただし、使用しているDotNetOpenAuthバージョンは、Googleが現在実装しているものとは異なるOAuth 2.0)のドラフトを実装しています。仕様がまだ確定していないため、どちらの部分も「正しい」ものではありませんが、互換性があります。悪夢のようなもの。

使用しているDotNetOpenAuthのバージョンが最新であることを確認できます(役立つ場合は可能性があります)が、最終的には、仕様が確定して全員が実装するまで、しっかりと座る必要があります。正しく、または自分でGoogleドキュメント(おそらくOAuth 2.0)のバージョンを説明している)を読んで、ドラフトバージョンを具体的に対象とするものを実装してください。

2
Andrew Arnott