首页 文章

Google API OAuth2,服务帐户,“错误”:“invalid_grant”

提问于
浏览
12

我正在尝试使用服务帐户将Dynamics CRM软件的日历同步到Google . 在此过程中,我遇到了关于.net的谷歌API缺乏文档,特别是关于授权 . 由于使用了过时的库和类,大多数Google样本都无法编译 .

所以我发现了一些关于实习和接收错误的例子 . Could someone please look on my sample and tell what am I doing wrong?

准备步骤:

  • 我在我的私人Google帐户中创建了一个项目 .

  • 在项目开发者控制台中,在APIS&AUTH - > Credentials下,我生成了服务帐户 . 然后单击"Generate P12 key"并下载.p12文件 .

  • 在APIS&AUTH - > API下,启用"Calendar API"

然后创建了控制台应用程序并设法安装OAuth和Calendar nuget包 . 有:

  • Google API Auth Client Library,Google.Apis.Auth 1.8.1

  • Google API客户端库,Google.Apis 1.8.1

  • Google API核心客户端库,Id:Google.Apis.Core 1.8.1

  • Google.APIs.Calendar.v3客户端库,Google.Apis.Calendar.V3 1.8.1.860

有一个代码可以找到并适应我的需求:

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 = "506310960175-q2k8hjl141bml57ikufinsh6n8qiu93b@developer.gserviceaccount.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();
        }
    }
}

我在应用和Fiddler中看到的与Google API的通信是:

要求:

主机:HTTPS accounts.google.com,URL:/ o / oauth2 / token断言:长二进制字符串grant_type:urn:ietf:params:oauth:grant-type:jwt-bearer

响应:

HTTP / 1.1 400 Bad Request Content-Type:application / json Cache-Control:no-cache,no-store,max-age = 0,must-revalidate Pragma:no-cache Expires:Fri,01 Jan 01 00:00 :00 GMT日期:星期四,2014年7月24日06:12:18 GMT X-Content-Type-Options:nosniff X-Frame-Options:SAMEORIGIN X-XSS-Protection:1; mode = block服务器:GSE Alternate-Protocol:443:quic Transfer-Encoding:chunked 1f {“error”:“invalid_grant”} 0

Fiddler screenshot

请提前帮助和感谢!

3 回答

  • 0

    经过一些调查后发现,Google API无法按预期使用您的个人帐户@ gmail.com . 您应该以Google @ your_organisation_domain格式在Google中拥有组织域帐户

    然后,这也很令人困惑,在Google Drive API page有文档,在Calendar API页面没有提到 "Delegate domain-wide authority to your service account" 部分 . 该部分有7个步骤,需要完成 .

    BTW与个人帐户管理网站admin.google.com甚至不可用 . 因此,使用@ gmail.com帐户执行这7个步骤是不可能的 .

    然后,当客户在Google Apps管理控制台>安全>高级设置>管理OAuth客户端访问权限中获得授权时,代码就会开始运行 .

    有一个适合我的代码:

    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 = "795039984093-c6ab1mknpediih2eo9cb70mc9jpu9h03@developer.gserviceaccount.com";
                var userAccountEmail = "me@testdomain.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
    
                });
    
                /* 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();
            }
        }
    }
    

    产生的输出看起来如此:

    Calendar via OAuth2 Service Account Sample
    Created event Id: jkits4dnpq6oflf99mfqf1kdo0
    calendar id=me@testdomain.com
    Event ID: 1logvocs77jierahutgv962sus, ICalUID: 1logvocs77jierahutgv962sus@google.com
      Name: test event
      Description: test description2
      Status: confirmed
      Color: 
      Attendees: 
      Kind: calendar#event
      Location: location2
      Organizer: me@testdomain.com
      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: 1logvocs77jierahutgv962sus@google.com
      Name: test event updated
      Description: test description2
      Status: confirmed
      Color: 
      Attendees: 
      Kind: calendar#event
      Location: location2
      Organizer: me@testdomain.com
      Recurrence: no recurrence
      Start: 2014-08-14
      End: 2014-08-15
      Reminders: Not defailt, email:10
    =====================
    Event ID: 974hqdhh8jhv5sdobkggmdvvd8, ICalUID: 974hqdhh8jhv5sdobkggmdvvd8@google.com
      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: me@testdomain.com
      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: jkits4dnpq6oflf99mfqf1kdo0@google.com
      Name: Calendar event via API
      Description: Programmatically created
      Status: confirmed
      Color: 6
      Attendees: 
      Kind: calendar#event
      Location: 
      Organizer: me@testdomain.com
      Recurrence: no recurrence
      Start: 2/08/2014 12:30:50 PM
      End: 2/08/2014 1:30:50 PM
      Reminders: Not defailt, popup:60
    =====================
    

    第一项活动是每周一次的全日活动系列 . 第二个是第一个更新的单个事件(具有相同的UID) . 第三是一小时的单一事件 . 最后一个是由上面的代码创建的 .

    希望这能帮助他人节省时间 .

  • 6

    由于服务帐户是您要登录的用户,因此需要发送 UserServiceAccountCredential . 我不确定你为什么要发送某人的Gmail电子邮件 .

    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 = "1046123799103-6v9cj8jbub068jgmss54m9gkuk4q2qu8@developer.gserviceaccount.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;
    
            }
        }
    }
    

    此代码经过测试,它向您展示了如何为服务帐户创建初始日历 . 如果不创建日历,它将返回0个日历,您需要记住先创建一个日历 .

  • 0

    我有同样的问题,它在远程服务器上工作正常,但在本地服务器上我得到了那个错误,长时间的故事短暂几小时的头痛我发现问题来自我的系统时钟,只是通过这些步骤

    1. Click on the clock in your system

    • 这将显示日历和时间

    2. Click Change date and time settings...

    • 将出现日期和时间对话框

    3. Click on the Internet Time tab

    4. Click Change settings

    • 将出现“Internet时间设置”对话框 .

    然后终于使用其中一个时间服务器更新你的时钟

相关问题