9

ここのサンプル コードに従いました: https://code.google.com/p/google-api-dotnet-client/wiki/OAuth2#Service_Accounts

認証が次のエラーで失敗する: DotNetOpenAuth.Messaging.ProtocolException: ダイレクト メッセージの送信中または応答の取得中にエラーが発生しました。

内部例外は System.Net.WebException です。リモート サーバーがエラーを返しました: (400) Bad Request。レスポンスの本文は空で、レスポンスの URI はhttps://accounts.google.com/o/oauth2/tokenです。

以下の応答では、特定のエラーが invalid_grant であることがわかります。

これが私のコードです:

var certificate = new X509Certificate2(CertificatePath, "notasecret", X509KeyStorageFlags.Exportable);
var provider = new AssertionFlowClient(GoogleAuthenticationServer.Description, certificate)
    {
        ServiceAccountId = "<...>@developer.gserviceaccount.com",
        Scope = CalendarService.Scopes.Calendar.GetStringValue()
    };

var authenticator = new OAuth2Authenticator<AssertionFlowClient>(provider, AssertionFlowClient.GetState);

var calendarService =
    new CalendarService(new BaseClientService.Initializer()
        {
            Authenticator = authenticator
        });

var eventList = calendarService.Events.List("<id of the calendar>").Execute();

証明書と ServiceAccountId が正しい。私はトリプルチェックを行い、適切な手段として証明書を再生成しました。Google カレンダー API は、サービス アカウントの作成に使用される Google 開発者アカウントの API コンソールで有効になっています。このアカウントは Google Apps ドメインの一部ではありません。

また、AssertionFlowClient の ServiceAccountUser プロパティを指定してこれをテストしました。私は今、これが必要であると信じています - 手動で作成された JWT を使用した CalendarService のテストに成功しました (以下の OAuth トークンの手動作成を参照)。 prn 属性が含まれていないトークンを作成しようとすると、404 エラーを受け取りました要求 (つまり、ServiceAccountUser は含まれません)。

Google Apps ドメインの設定

Google Apps ドメインで、このサービス アカウントにカレンダーへのアクセスを許可しました。

クライアント名: [中略].apps.googleusercontent.com

API スコープ:

インストールされた NuGet パッケージ

  • Google.Apis (1.5.0-ベータ)
  • Google.Apis.Calendar.v3 (1.5.0.59-ベータ版)
  • Google.Apis.Authentication (1.5.0-ベータ)

リクエストとレスポンス

POST https://accounts.google.com/o/oauth2/token HTTP/1.1
Content-Type: application/x-www-form-urlencoded; charset=utf-8
User-Agent: DotNetOpenAuth/4.0.0.11165
Host: accounts.google.com
Cache-Control: no-store,no-cache
Pragma: no-cache
Content-Length: 606
Connection: Keep-Alive

grant_type=assertion&assertion_type=http%3A%2F%2Foauth.net%2Fgrant_type%2Fjwt%2F1.0%2Fbearer&assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI5NzUzOTk3NzMyNi01NHFvMXY4OW5iZTk4dGNlbGIycWY0cDdjNThzYjhmMkBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNjb3BlIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vYXV0aC9jYWxlbmRhciIsImF1ZCI6Imh0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbS9vL29hdXRoMi90b2tlbiIsImV4cCI6MTM3OTU5MTA4MywiaWF0IjoxMzc5NTg3NDgzfQ.Ls_sv40MfB8MAD92JFcFiW5YYoRytQ3e2PA8RV_hn4FJfVHDo6uCSunN7950H2boO6LfX9EMrpjaf8ZyNyHyrQucQaWwfIFD6F2FpnqlcNkzXoqWMCwkt-k-8ypGMSZfFCEkhw8QOrlIPFZb6qx61689n08G9tZMTzHGYc2b8Gk

よく調べてみると、アサーションは正しく、ここでデコードされているように見えます。

{"alg":"RS256","typ":"JWT"}{"iss":"97539977326-54qo1v89nbe98tcelb2qf4p7c58sb8f2@developer.gserviceaccount.com","scope":"https://www.googleapis.com/auth/calendar","aud":"https://accounts.google.com/o/oauth2/token","exp":1379591083,"iat":1379587483}

HTTP/1.1 400 Bad Request
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: Fri, 01 Jan 1990 00:00:00 GMT
Date: Thu, 19 Sep 2013 10:44:42 GMT
Content-Type: application/json
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
Server: GSE
Alternate-Protocol: 443:quic
Content-Length: 31

{
  "error" : "invalid_grant"
}

OAuthトークン作品の手動作成

セットアップが正しく行われたことを確認するために、google-oauth-jwt (ここではhttps://github.com/extrabacon/google-oauth-jwt ) を使用して手動でトークンを作成しました。上記のコードで使用しているのと同じ属性を使用して、トークンを正常に作成できました。トークンを作成してカスタム IAuthenticator で使用すると、ターゲットの Google Apps ドメインのユーザーのカレンダーからイベントを正常に取得できます。ご参考までに、カレンダーへのアクセスはサービス アカウントで可能です。

Authorization ヘッダーを追加するだけの IAuthenticator 実装を次に示します。

public class Authenticator : IAuthenticator
{
  public void ApplyAuthenticationToRequest(System.Net.HttpWebRequest request)
  {
    request.Headers.Add(HttpRequestHeader.Authorization, "Bearer <token here>");
  }
}
4

3 に答える 3

2

この質問が出されてから何かが変わったかどうかはわかりませんが、実際に Google カレンダーはサービス アカウントをサポートしています。

Google カレンダー API で使用するサービス アカウントを設定する場合、必要なのはサービス アカウントのメール アドレスだけです。Google カレンダーの Web サイトにアクセスします。カレンダー設定 を見つけて、カレンダー タブに移動し、アクセスしたいカレンダーを見つけて、[共有: 設定の編集] をクリックします。個人のメール アドレスと同じように、サービス アカウントのメール アドレスを追加します。これにより、他のユーザーと共有している場合と同じアクセス権がサービス アカウントに付与されます。

string[] scopes = new string[] {
    CalendarService.Scope.Calendar, // Manage your calendars
    CalendarService.Scope.CalendarReadonly // View your Calendars
 };

 var certificate = new X509Certificate2(keyFilePath, "notasecret", X509KeyStorageFlags.Exportable);

ServiceAccountCredential credential = new ServiceAccountCredential(
    new ServiceAccountCredential.Initializer(serviceAccountEmail) {
        Scopes = scopes
    }.FromCertificate(certificate));

// Create the service.
    CalendarService service = new CalendarService(new BaseClientService.Initializer() {
        HttpClientInitializer = credential,
        ApplicationName = "Calendar API Sample",
    });

Google カレンダー API 認証 C#から切り取ったコード

于 2014-12-17T13:32:26.003 に答える
1

私が知っているように、カレンダー サービスはサービス アカウントをサポートしていません。

G+ サンプルが機能するかどうか ( https://code.google.com/p/google-api-dotnet-client/source/browse/Plus.ServiceAccount/Program.cs?repo=samples ) を同じコードで確認できます。 Calendar API のためにここで実行しようとしています。Google plus はサービス アカウントをサポートしているため、動作するはずです。

サービス アカウントの代わりに OAuth2 ユーザー フローを実行できないのはなぜですか?

更新: 結局のところ、Calendar API サポート サービス アカウントです。混乱させて申し訳ありません。

于 2013-09-21T00:10:10.950 に答える