it-swarm.com.de

Google API OAuth2, Dienstkonto, "Fehler": "invalid_grant"

Ich versuche, das Dienstkonto für die Synchronisierung von Kalendern aus der Dynamics CRM-Software mit Google zu verwenden .. Während dieser Zeit war ich mit der Dokumentation zu Google API für .net konfrontiert, insbesondere hinsichtlich der Autorisierung. Die meisten Google-Beispiele können aufgrund von veralteten Bibliotheken und Klassen nicht einmal kompiliert werden.

Also habe ich ein Beispiel über interned gefunden und erhalte Fehler. Könnte jemand bitte auf meine Probe schauen und sagen, was ich falsch mache?

Vorbereitende Schritte:

  1. Ich habe ein Projekt in meinem privaten Google-Konto erstellt.
  2. In der Projektentwicklungskonsole unter APIS & AUTH -> Anmeldeinformationen habe ich ein Servicekonto erstellt. Klicken Sie dann auf "P12-Schlüssel generieren" und laden Sie die P12-Datei herunter.
  3. Unter APIS & AUTH -> APIs auf "Kalender-API" umgestellt

Anschließend wurde eine Konsolen-App erstellt und die Installation von OAuth- und Calendar-Nuget-Paketen wurde durchgeführt. Es gibt:

  1. Google APIs Auth Client Library, Google.Apis.Auth 1.8.1
  2. Google APIs Client Library, Google.Apis 1.8.1
  3. Google APIs-Core-Client-Bibliothek, Id: Google.Apis.Core 1.8.1
  4. Google.APIs.Calendar.v3 Client Library, Google.Apis.Calendar.V3 1.8.1.860

Es wurde ein Code gefunden und an meine Bedürfnisse angepasst:

using System;
using System.Security.Cryptography.X509Certificates;
using Google.Apis.Calendar.v3;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Services;

namespace CrmToGoogleCalendar
{
    class Program
    {

        static void Connect()
        {
            var certificate = new X509Certificate2("My Project-ee7facaa2bb1.p12", "notasecret", X509KeyStorageFlags.Exportable);


            var serviceAccountEmail = "[email protected]account.com";
            var userAccountEmail = "<my email>@gmail.com";
            var credential = new ServiceAccountCredential(new ServiceAccountCredential.Initializer(serviceAccountEmail) 
                {
                    User = userAccountEmail,
                    Scopes = new[] { CalendarService.Scope.Calendar }
                }
                .FromCertificate(certificate));

            var service = new CalendarService(new BaseClientService.Initializer()
            {
                ApplicationName = "Test calendar sync app",
                HttpClientInitializer = credential

            });

            var calList = service.CalendarList.List().Execute().Items;


            foreach (var cal in calList)
            {
                Console.WriteLine(cal.Id);
            }
        }


        static void Main(string[] args)
        {
            Connect();
        }
    }
}

Die Kommunikation mit der Google-API, die ich in der App und mit Fiddler sehe, ist:

Anfrage:

Host: HTTPS-Accounts.google.com, URL:/o/oauth2/token
Behauptung: langer binärer String
grant_type: urn: ietf: params: oauth: grant-type: jwt-bearer

Antwort:

HTTP/1.1 400 Fehlerhafte Anforderung Inhaltstyp: application/json Cache-Control: no-cache, no-store, max-age = 0, Muss-Überprüfung von Pragma: no-cache Gültig bis: Fr, 01. Januar 1990 00:00:00 GMT Datum: Do 24 Jul 2014 06:12:18 GMT X-Content-Type-Optionen: nosniff X-Frame-Optionen: SAMEORIGIN X-XSS-Schutz: 1; Modus = Block Server: GSE Alternate-Protocol: 443: quic Transfer-Encoding: chunked

1f {"error": "invalid_grant"} 0

Fiddler screenshot

Bitte helfen und danke im Voraus!

12
Dimitry

Nach einigen Nachforschungen stellte ich fest, dass die Google-API mit Ihrem persönlichen Konto @ gmail.com nicht wie erwartet funktioniert. Sie sollten ein Organisationsdomänenkonto bei Google im Format Sie @ Ihre_organisation_Domäne haben

Was auch ziemlich verwirrend ist, gibt es eine Dokumentation auf der Google Drive API-Seite , mit "Domänenweite Berechtigung an Ihr Dienstkonto delegieren" Abschnitt, der auf der Kalender-API-Seite nicht erwähnt wird . Es gibt 7 Schritte in dem Abschnitt, die erledigt werden müssen. 

BTW mit der persönlichen Konto-Administrationsseite admin.google.com ist sogar nicht verfügbar. Es ist daher unmöglich, diese 7 Schritte mit dem Konto @ gmail.com auszuführen. 

Wenn der Client in Google Apps Admin Console> Sicherheit> Erweiterte Einstellungen> OAuth-Clientzugriff verwalten} autorisiert ist, _ beginnt der Code zu funktionieren. 

Es gibt einen Code, der für mich funktioniert:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using Google.Apis.Calendar.v3;
using Google.Apis.Calendar.v3.Data;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Services;

namespace CrmToGoogleCalendar
{
    class Program
    {

        static void Connect()
        {
            Console.WriteLine("Calendar via OAuth2 Service Account Sample");

            var certificate = new X509Certificate2("My MC Project-3f38defdf4e4.p12", "notasecret", X509KeyStorageFlags.Exportable);
            var serviceAccountEmail = "[email protected]account.com";
            var userAccountEmail = "[email protected]"; 
            var credential = new ServiceAccountCredential(new ServiceAccountCredential.Initializer(serviceAccountEmail) 
                {
                    User = userAccountEmail,
                    Scopes = new[] { CalendarService.Scope.Calendar }
                }
                .FromCertificate(certificate));

            var service = new CalendarService(new BaseClientService.Initializer()
            {
                ApplicationName = "Test calendar sync app",
                HttpClientInitializer = credential

            });

            /* Get list of calendars */
            var calList = service.CalendarList.List().Execute().Items;
            var myCalendar = calList.First(@c => @c.Id == userAccountEmail);

            /* CREATE EVENT */
            var event1 = new Event()
                {
                    Kind = "calendar#event",
                    Summary = "Calendar event via API",
                    Description = "Programmatically created",
                    Status = "confirmed",
                    Organizer = new Event.OrganizerData() {
                        Email = userAccountEmail
                    },
                    Start = new EventDateTime()
                        {
                            DateTime = DateTime.Now.AddDays(1)
                        },
                    End = new EventDateTime()
                    {
                        DateTime = DateTime.Now.AddDays(1).AddHours(1)
                    },
                    ColorId = "6",
                    Reminders = new Event.RemindersData()
                        {
                            UseDefault = false,
                            Overrides = new List<EventReminder>(
                                new [] {
                                    new EventReminder()
                                        {
                                            Method = "popup",
                                            Minutes = 60
                                        }
                                })
                        }
                };

            event1 = service.Events.Insert(event1, myCalendar.Id).Execute();
            Console.WriteLine("Created event Id: {0}", event1.Id);


            /* ENLIST EVENTS */
            Console.WriteLine("calendar id={0}", myCalendar.Id);
            var events = service.Events.List(myCalendar.Id).Execute();
            foreach (var @event in events.Items)
            {
                Console.WriteLine("Event ID: {0}, ICalUID: {1}", @event.Id, @event.ICalUID);
                Console.WriteLine("  Name: {0}", @event.Summary);
                Console.WriteLine("  Description: {0}", @event.Description);
                Console.WriteLine("  Status: {0}", @event.Status);
                Console.WriteLine("  Color: {0}", @event.ColorId);
                Console.WriteLine("  Attendees: {0}", @event.Attendees == null ? "" : @event.Attendees.Select(a => a.Email).ToString());
                Console.WriteLine("  Kind: {0}", @event.Kind);
                Console.WriteLine("  Location: {0}", @event.Location);
                Console.WriteLine("  Organizer: {0}", @event.Organizer.Email);
                Console.WriteLine("  Recurrence: {0}", @event.Recurrence == null ? "no recurrence" : String.Join(",", @event.Recurrence));
                Console.WriteLine("  Start: {0}", @event.Start.DateTime == null ? @event.Start.Date : @event.Start.DateTime.ToString());
                Console.WriteLine("  End: {0}", @event.End.DateTime == null ? @event.End.Date : @event.End.DateTime.ToString());
                Console.WriteLine("  Reminders: {0}", @event.Reminders.UseDefault.Value ? "Default" : "Not defailt, " + 
                    (@event.Reminders.Overrides == null ? "no overrides" : String.Join(",", @event.Reminders.Overrides.Select(reminder => reminder.Method + ":" + reminder.Minutes)))
                    );
                Console.WriteLine("=====================");
            }

            Console.ReadKey();
        }


        static void Main(string[] args)
        {
            Connect();
        }
    }
}

Die Ausgabe sieht so aus:

Calendar via OAuth2 Service Account Sample
Created event Id: jkits4dnpq6oflf99mfqf1kdo0
calendar [email protected]
Event ID: 1logvocs77jierahutgv962sus, ICalUID: [email protected]
  Name: test event
  Description: test description2
  Status: confirmed
  Color: 
  Attendees: 
  Kind: calendar#event
  Location: location2
  Organizer: [email protected]
  Recurrence: RRULE:FREQ=WEEKLY;BYDAY=TH
  Start: 2014-07-31
  End: 2014-08-01
  Reminders: Not defailt, email:10,popup:10
=====================
Event ID: 1logvocs77jierahutgv962sus_20140814, ICalUID: [email protected]
  Name: test event updated
  Description: test description2
  Status: confirmed
  Color: 
  Attendees: 
  Kind: calendar#event
  Location: location2
  Organizer: [email protected]
  Recurrence: no recurrence
  Start: 2014-08-14
  End: 2014-08-15
  Reminders: Not defailt, email:10
=====================
Event ID: 974hqdhh8jhv5sdobkggmdvvd8, ICalUID: [email protected]
  Name: One hour event
  Description: test description
  Status: confirmed
  Color: 7
  Attendees: 
  Kind: calendar#event
  Location: Meeting Room Hire, Broadway, 255 The Bdwy, Broadway, NSW 2007, Australia
  Organizer: [email protected]
  Recurrence: no recurrence
  Start: 1/08/2014 10:00:00 AM
  End: 1/08/2014 11:00:00 AM
  Reminders: Default
=====================
Event ID: jkits4dnpq6oflf99mfqf1kdo0, ICalUID: [email protected]
  Name: Calendar event via API
  Description: Programmatically created
  Status: confirmed
  Color: 6
  Attendees: 
  Kind: calendar#event
  Location: 
  Organizer: [email protected]
  Recurrence: no recurrence
  Start: 2/08/2014 12:30:50 PM
  End: 2/08/2014 1:30:50 PM
  Reminders: Not defailt, popup:60
=====================

Das erste Ereignis ist eine wöchentliche Ganztagsereignisreihe . Das zweite Ereignis wird einzeln aktualisiert (mit derselben UID) . Das dritte Ereignis ist ein einzelnes Ereignis für eine Stunde . Das letzte Ereignis wird durch den obigen Code erstellt.

Ich hoffe, das hilft anderen, ihre Zeit zu sparen.

6
Dimitry

ich hatte dasselbe Problem, es funktionierte gut auf Remote-Servern, aber auf dem lokalen Server kam ich zu diesem Fehler. Lange Geschichte, kurz nach Stunden von Kopfschmerzen, fand ich heraus, dass das Problem von meiner Systemuhr war. Gehen Sie einfach durch diese Schritte 

1. Klicken Sie auf die Uhr in Ihrem System

  • Dadurch werden Kalender und Uhrzeit angezeigt 

2. Klicken Sie auf Datums- und Uhrzeiteinstellungen ändern ...

  • Das Dialogfeld "Datum und Uhrzeit" wird angezeigt

3. Klicken Sie auf die Registerkarte Internetzeit

4. Klicken Sie auf Einstellungen ändern

  • Das Dialogfeld "Internetzeiteinstellungen" wird angezeigt.

aktualisieren Sie anschließend Ihre Uhr mit einem der Zeitserver

0
Abolfazl

Ich bin nicht wirklich sicher, was mit Ihrem Code falsch ist. Ich denke, es ist ein Teil, wie Sie die Schlüsseldatei laden. Es könnte auch die Tatsache sein, dass Sie User mit ServiceAccountCredential nicht senden müssen, da das Dienstkonto der Benutzer ist, bei dem Sie sich anmelden. Ich weiß nicht, warum Sie jemandem eine Gmail-E-Mail senden. 

using Google.Apis.Auth.OAuth2;
using System.Security.Cryptography.X509Certificates;
using Google.Apis.Calendar.v3;
namespace GoogleAnalytics.Service.Account
{
    class Program
    {
        static void Main(string[] args)
        {
            //Install-Package Google.Apis.Calendar.v3
            string serviceAccountEmail = "[email protected]eaccount.com";
            var certificate = new X509Certificate2(@"C:\Users\HP_User\Documents\GitHub\Google-Analytics-dotnet-ServiceAccount\GoogleAnalytics.Service.Account\Diamto Test Everything Project-bc63fd995bd7.p12", "notasecret", X509KeyStorageFlags.Exportable);

            ServiceAccountCredential credential = new ServiceAccountCredential(
                   new ServiceAccountCredential.Initializer(serviceAccountEmail)
                   {
                       Scopes = new[] { CalendarService.Scope.Calendar }
                   }.FromCertificate(certificate));

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

            // define the new Calendar
            Google.Apis.Calendar.v3.Data.Calendar calendar = new Google.Apis.Calendar.v3.Data.Calendar();
            calendar.Description = "New Calendar";
            calendar.Summary = "New Calendar Summary";
            // Insert the Calendar
            service.Calendars.Insert(calendar).Execute();
            // List The Calendar
            var calList = service.CalendarList.List().Execute().Items;

        }
    }
}

Dieser Code wurde getestet und zeigt Ihnen, wie Sie den Anfangskalender für das Dienstkonto erstellen. Wenn Sie keinen Kalender erstellen, werden 0 Kalender zurückgegeben. Sie müssen daran denken, zuerst einen Kalender zu erstellen.

0
DaImTo