web-dev-qa-db-ja.com

C#のサービスアカウントでGoogle APIにログインする方法-資格情報が無効です

私は、C#、Google API、およびGoogle Analyticsで動作する簡単なサービスアカウントログインを取得しようとして、血まみれになっています。私の会社はすでにアナリティクスにデータを取得しており、Query Explorerで情報をクエリできますが、.Netで始めるのはどこにも行きません。ドキュメントでは、そのようなサービスアカウントがGoogla APIとのコンピューター間通信に適した方法であると述べているため、PKIでGoogleが生成したjsonファイルを使用しています。コードスニペット:

public static GoogleCredential _cred;
public static string _exePath;

static void Main(string[] args) {
    _exePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase).Replace(@"file:\", "");
    var t = Task.Run(() => Run());
    t.Wait();
}

private static async Task Run() {
    try {
        // Get active credential
        using (var stream = new FileStream(_exePath + "\\Default-GASvcAcct-508d097b0bff.json", FileMode.Open, FileAccess.Read)) {
            _cred = GoogleCredential.FromStream(stream);
        }
        if (_cred.IsCreateScopedRequired) {
        _cred.CreateScoped(new string[] { AnalyticsService.Scope.Analytics });
        }
        // Create the service
        AnalyticsService service = new AnalyticsService(
            new BaseClientService.Initializer() {
                HttpClientInitializer = _cred,
            });
        var act1 = service.Management.Accounts.List().Execute(); // blows-up here

すべて正常にコンパイルされますが、Execute()ステートメントにヒットすると、GoogleApiExceptionエラーがスローされます。

[無効な資格情報]場所[承認-ヘッダー]理由[authError]ドメイン[グローバル]

不足しているものは何ですか?

18
Vic Lindsey

GoogleAnalyticsはジェネリックGoogleCredentialを消費してServiceAccountCredentialとして解釈することはできないようです(実際にはそのタイプの)。したがって、ServiceAccountCredentialを作成する必要があります。 GoogleCredentialがクレデンシャルのさまざまなプロパティを公開しないことも残念なため、独自に作成する必要がありました。

JSON C#Class Generatorを http://jsonclassgenerator.codeplex.com/ で使用して、Google APIの自動部分であるJSONライブラリを使用して「パーソナル」ServiceAccountCredentialオブジェクトを構築しました(Newtonsoft.Json)、サービスアカウントのダウンロードされたjsonファイルの重要な部分を取得し、その電子メールと秘密キーのプロパティを使用して、必要な資格情報を構築しました。正規のServiceAccountCredentialをGoogleAnalyticsサービスコンストラクターに渡すと、ログインが成功し、そのアカウントの許可されたリソースにアクセスできます。

以下の作業コードのサンプル:

using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Text;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Services;
using Google.Apis.Analytics.v3;
using Newtonsoft.Json;
    .
    .
    .
try
{
    // Get active credential
    string credPath = _exePath + @"\Private-67917519b23f.json";

    var json = File.ReadAllText(credPath);
    var cr = JsonConvert.DeserializeObject<PersonalServiceAccountCred>(json); // "personal" service account credential

    // Create an explicit ServiceAccountCredential credential
    var xCred = new ServiceAccountCredential(new ServiceAccountCredential.Initializer(cr.ClientEmail)
    {
        Scopes = new[] {
            AnalyticsService.Scope.AnalyticsManageUsersReadonly,
            AnalyticsService.Scope.AnalyticsReadonly
        }
    }.FromPrivateKey(cr.PrivateKey));

    // Create the service
    AnalyticsService service = new AnalyticsService(
        new BaseClientService.Initializer()
        {
            HttpClientInitializer = xCred,
        }
    );

    // some calls to Google API
    var act1 = service.Management.Accounts.List().Execute();

    var actSum = service.Management.AccountSummaries.List().Execute();

    var resp1 = service.Management.Profiles.List(actSum.Items[0].Id, actSum.Items[0].WebProperties[0].Id).Execute();

PKI(Private Key)を使用してGoogleが生成したサービスアカウント資格情報がどのようなものか疑問に思うかもしれません。 https://console.developers.google.com/iam-admin/projects のGoogle API Manager(IAMおよび管理者)から、適切なプロジェクトを選択します(これらの少なくとも1つがあります)。次に、サービスアカウント(左のナビゲーションリンクから)、およびCREATE SERVICE ACCOUNT画面の上部。名前を入力し、新しい秘密キーを入力するチェックボックスを設定して、作成。 Googleは、次のようなJSONファイルの自動ダウンロードを引き起こします。

{
  "type": "service_account",
  "project_id": "atomic-acrobat-135",
  "private_key_id": "508d097b0bff9e90b8d545f984888b0ef31",
  "private_key": "-----BEGIN PRIVATE KEY-----\nMIIE...o/0=\n-----END PRIVATE KEY-----\n",
  "client_email": "[email protected]",
  "client_id": "1123573016559832",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://accounts.google.com/o/oauth2/token",
  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
  "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/google-analytics%40atomic-acrobat-135923.iam.gserviceaccount.com"
}
23
Vic Lindsey

指定したスコープが実際に資格情報で送信されていないため、無効な資格情報エラーが発生しています。私は同じ間違いを犯しましたが、デバッグ後に初めて気づきましたが、CreateScoped呼び出し後も資格情報に0のスコープが表示されました。

GoogleCredentialは不変なので、CreateScopedは指定されたスコープセットで新しいインスタンスを作成します。

そのようにスコープされた結果で資格情報変数を再割り当てし、それが機能するはずです:

  if (_cred.IsCreateScopedRequired) {
    _cred = _cred.CreateScoped(AnalyticsService.Scope.Analytics);
  }

受け入れられた答えは、同じことをより困難な方法で達成しているために機能します。

0
dlumpp

別のオプションは、GoogleCredential.GetApplicationDefault()を使用することです。これは現在(2018年10月)推奨されているアプローチだと思います。以下にいくつかのF#を示しますが、C#モジュロ構文でもほぼ同じです。

let projectId = "<your Google Cloud project ID...>"
let creds =
  GoogleCredential.GetApplicationDefault()
    .CreateScoped(["https://www.googleapis.com/auth/cloud-platform"])
use service =
  new CloudBuildService(
    BaseClientService.Initializer(HttpClientInitializer=creds))
let foo = service.Projects.Builds.List(projectId).Execute()

ここで、GOOGLE_APPLICATION_CREDENTIALSクレデンシャルJSONファイルを含むファイルを指す、たとえば。 GOOGLE_APPLICATION_CREDENTIALS=creds.json dotnet run

0
skainswo