web-dev-qa-db-fra.com

Comment se connecter à l'API Google avec un compte de service en C # - Informations d'identification non valides

Je me bat de façon sanglante en essayant d'obtenir un compte simple de connexion pour pouvoir travailler en C #, vers Google API et Google Analytics. Mon entreprise intègre déjà des données dans Analytics et je peux interroger des informations à l'aide de leur explorateur de requêtes, mais démarrer dans .Net ne va nulle part. J'utilise un fichier json généré par Google avec PKI, car la documentation indique qu'un tel compte de service est le moyen approprié pour la communication entre ordinateurs avec l'API Googla. Morceau de code:

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

Tout se compile bien, mais quand il frappe l'instruction Execute (), une erreur GoogleApiException est levée:

[Informations d'identification non valides] Emplacement [Autorisation - en-tête] Raison [authError] Domaine [global]

Qu'est-ce que je rate?

18
Vic Lindsey

Il semble que GoogleAnalytics ne puisse pas consommer une GoogleCredential générique et l’interpréter comme une ServiceAccountCredential (même s’il est notifié, de manière interne, qu’il s’agit bien de de ce type). Ainsi, vous devez créer une variable ServiceAccountCredential à la dure. Il est également regrettable que GoogleCredential n’expose pas les différentes propriétés du justificatif. J’ai donc dû créer la mienne.

J'ai utilisé le générateur de classes JSON C # à l 'adresse http://jsonclassgenerator.codeplex.com/ pour créer un objet "personnel" ServiceAccountCredential à l' aide de la bibliothèque JSON faisant automatiquement partie de Google API (Newtonsoft. Json), récupéré les parties essentielles du fichier json téléchargé du compte de service, afin de construire les informations d'identification requises, à l'aide de ses propriétés de courrier électronique et de clé privée. En transmettant une valeur ServiceAccountCredential authentique au constructeur de service GoogleAnalytics, la connexion aboutit et l'accès aux ressources autorisées de ce compte.

Exemple de code de travail ci-dessous:

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

Certains peuvent se demander à quoi ressemble un identifiant de compte de service généré par Google avec PKI (clé privée). Dans le Gestionnaire des API Google (IAM & Admin) à l'adresse https://console.developers.google.com/iam-admin/projects , sélectionnez le projet approprié (vous en avez au moins un). Sélectionnez maintenant Comptes de service (à partir des liens de navigation de gauche), et CREATE SERVICE ACCOUNT en haut de l'écran. Entrez un nom, cochez la case Fournir une nouvelle clé privée, puis cliquez sur Créer. Google provoquera le téléchargement automatique d'un fichier JSON, qui ressemble à ceci:

{
  "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

L'erreur d'informations d'identification non valide se produit car les étendues que vous avez spécifiées ne sont pas réellement envoyées avec vos informations d'identification. J'ai fait la même erreur et je ne me suis rendu compte qu'après avoir débogué et vu toujours 0 étendue sur les informations d'identification après l'appel CreateScoped.

Une GoogleCredential étant immuable, CreateScoped crée une nouvelle instance avec le jeu d'étendues spécifié.

Réaffectez votre variable d’informations d’identité avec le résultat de portée tel quel et cela devrait fonctionner:

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

La réponse acceptée fonctionne parce que la même chose est accomplie de manière plus difficile. 

0
dlumpp

Une autre option consiste à utiliser GoogleCredential.GetApplicationDefault(). Je crois que c'est l'approche recommandée (octobre 2018). Voici quelques F #, mais c'est plus ou moins la même chose dans la syntaxe modulo 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()

Maintenant, assurez-vous que vous définissez le GOOGLE_APPLICATION_CREDENTIALS pour qu'il pointe vers le fichier contenant le fichier JSON d'informations d'identification, par exemple GOOGLE_APPLICATION_CREDENTIALS=creds.json dotnet run.

0
skainswo