无法以编程方式验证Google Calendar API v3?

时间:2014-07-13 04:07:14

标签: c# oauth google-calendar-api google-api-dotnet-client

也许我是唯一认为Google的API文档很糟糕的人,但我花了更多时间在这个简单的任务上,而不是我想要的。

目前,我的项目正在使用GDATA实施来连接Google Calendar API v2。我遵循了这个指南:http://www.codeproject.com/Articles/565032/Google-Calendar-Integration-in-ASP-NET-Create-ed

但是我注意到谷歌今年秋天正在弃用其API的第2版。我试图弄清楚如何连接到他们的版本3 API似乎使用OAuth2。

阅读完他们的文档并在互联网上搜索> :( - 我遇到的问题是每个示例,教程或youtube视频我都会看到如何实现这一点,这涉及用户点击的Google同意屏幕“接受”。

我尝试过以下但真的不确定它是否是正确的方向?

    // Register the authenticator. The Client ID and secret have to be copied from the API Access
    // tab on the Google APIs Console.
    var provider = new NativeApplicationClient(GoogleAuthenticationServer.Description);
    provider.ClientIdentifier = "MY_CLIENT_ID";
    provider.ClientSecret = "MY_CLIENT_SECRET";

    // Create the service. This will automatically call the previously registered authenticator.
    var service = new CalendarService();

我的应用程序不需要用户的帐户/同意(OAuth),我需要像我目前在代码隐藏中那样进行连接。

所以问题是我如何将当前的实现“升级”到v3?我是否使用OAuth,服务帐户?我发现大量示例显示了如何检索事件并插入事件的v3用法......但它们都通过前端的用户同意屏幕进行身份验证。

这是我目前的GData实施......

public class GoogleGateway : IGoogleGateway
    {
        private readonly IRepository<UserSetting> _settingsRepository;
        private Service _googleService;
        private CalendarService _googleCalendar;
        private Uri _calendarUri;

        public GoogleGateway(IRepository<UserSetting> settingsRepository)
        {
            _settingsRepository = settingsRepository;
        }

        public IEnumerable<EventEntry> GetAllEvents(DateTime? startDate)
        {
            if (!Connect()) return new List<EventEntry>();

            // Create the query object:
            EventQuery query = new EventQuery();
            query.Uri = _calendarUri;
            if (startDate != null)
                query.StartTime = startDate.Value;

            // Tell the service to query:
            EventFeed calFeed = _googleCalendar.Query(query);
            return calFeed.Entries.Cast<EventEntry>();
        }

        public bool Connect()
        {
            var calSettings = _settingsRepository.Get().Where(x => x.Setting == "Calendar");

            if (calSettings.Any())
            {
                var username = calSettings.First(x => x.Meta == "GoogleUsername").Value;
                var password = calSettings.First(x => x.Meta == "GooglePassword").Value;
                var calendarUri = new Uri(calSettings.First(x => x.Meta == "CalendarFeed").Value);
                var applicationName = calSettings.First(x => x.Meta == "ApplicationName").Value;

                _calendarUri = calendarUri;

                //FeedQuery feedQuery = new FeedQuery();

                _googleService = new Service("cl", applicationName);
                _googleCalendar = new CalendarService(applicationName);

                // Set your credentials:
                _googleService.setUserCredentials(username, password);
                _googleCalendar.setUserCredentials(username, password);

                return true;
            }

            return false;
        }

        public void AddEvent(string title, string contents, string location, DateTime startTime, DateTime endTime)
        {
            if (!Connect()) return;

            EventEntry.EVENT_CATEGORY = new AtomCategory("Appointments");
            EventEntry entry = new EventEntry
            {
                Title = { Text = title },
                Content = { Content = contents },
            };

            // Set the title and content of the entry.

            // Set a location for the event.
            Where eventLocation = new Where();
            eventLocation.ValueString = location;
            entry.Locations.Add(eventLocation);

            When eventTime = new When(startTime, endTime);
            entry.Times.Add(eventTime);

            Uri postUri = new Uri("http://www.google.com/calendar/feeds/default/private/full");

            // Send the request and receive the response:
            AtomEntry insertedEntry = _googleCalendar.Insert(postUri, entry);
        }

        public void DeleteEvent(string eventId)
        {
            if (!Connect()) return;

            var events = GetAllEvents(null);

            var appointment = events.First(x => x.EventId == eventId);
            _googleService.Delete(appointment);
        }
    }

我在这一点上越来越绝望,任何帮助都会非常感激。在你的答案中包含你的推特手柄,我会给你买一杯咖啡!

已更新 我目前有以下内容,但我仍未进行身份验证...... :(

    static CalendarService BuildService()
    {
        String serviceAccountEmail = "xxxxxxxxxxxxx-31xxxxxxxxxxxxxxxxxxx@developer.gserviceaccount.com";

        var certPath = HttpContext.Current.Server.MapPath("/xxxxxxxxxxxx.p12");
        var certificate = new X509Certificate2(certPath, "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 BaseClientService.Initializer()
        {
            HttpClientInitializer = credential, <<<<<< DOES NOT RESOLVE!
            ApplicationName = "MyApplication",
        });

        var test = service.Calendars.Get("xxxxxxxxxxxxxxxxxx@group.calendar.google.com");

        return service;
    }

1 个答案:

答案 0 :(得分:2)

问题是您以明文形式存储凭证。在Oauth2中,用户不会向您提供凭据(因此可以访问所有内容),而是让您的应用程序访问特定类型/范围的数据。

从您的描述中不清楚您是否只在控件中完全访问一个日历,或者您有多个用户。在第一种情况下,答案将是使用服务帐户(https://developers.google.com/accounts/docs/OAuth2ServiceAccount)。在第二种情况下,如果您是一个拥有许多用户的日历应用程序,则需要沿着用户同意的道路前进,您应继续阅读:)

对于脱机访问,您可以指定在首次检索凭据时access_type应处于脱机状态。与访问令牌一起,您还将获得刷新令牌,您可以使用该令牌在以后重新进行身份验证,而无需再点击用户(https://developers.google.com/accounts/docs/OAuth2WebServer#refresh)。但是,至少有一个同意屏幕。