【问题标题】:.NET Google Calendar API v3 : mutilple account authentification.NET Google Calendar API v3:多帐户身份验证
【发布时间】:2013-12-16 23:12:55
【问题描述】:

我正在尝试编写一个程序来同步多个 Google 帐户的 CRM 和 Google 日历之间的事件。

这是一个 Windows 控制台应用程序。

对于每个 Google 帐户,我在 API 控制台中启用了日历 API,创建了一个名为“UpdateSync”(类型:本机)的应用程序,然后下载了 JSON 文件。

我使用帐户邮件地址(即 email1@gmail.com.json)重命名了这些文件

接下来,我写了下面的代码:

    /// <summary>
    /// Loads updated event from Google Calender after last synchonization date
    /// </summary>
    /// <param name="user">The user we want to get appointments</param>
    public List<Appointment> LoadAppointments(User user)
    {
        Console.WriteLine("LoadAppointments({0})", user.Email);
        List<Appointment> Appointments = new List<Appointment>();

        UserCredential credential;
        using (var stream = new FileStream(string.Format("credentials\\{0}.json", user.Email), FileMode.Open, FileAccess.Read))
        {
            try
            {
                credential = GoogleWebAuthorizationBroker.AuthorizeAsync(GoogleClientSecrets.Load(stream).Secrets, new[] { CalendarService.Scope.Calendar }, "user", CancellationToken.None, new FileDataStore("UpdayeSync.Credentials")).Result;
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                return null;
            }
        }

        BaseClientService.Initializer initializer = new BaseClientService.Initializer();
        initializer.HttpClientInitializer = credential;
        initializer.ApplicationName = "UpdateSync";
        service = new CalendarService(initializer);

        EventsResource.ListRequest req = service.Events.List("primary");
        req.TimeMin = DateTime.Now.AddMonths(-2).ToString("o");
        req.ShowDeleted = true;
        req.UpdatedMin = XmlConvert.ToString(LastSync, XmlDateTimeSerializationMode.Utc);
        req.SingleEvents = true;

        Events events;
        try
        {
            events = req.Execute();
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
            return null;
        }

        // [...]
    }

为每个 JSON 文件调用此代码。

第一次通话时,要同步的帐户是“email1@gmail.com”。 谷歌浏览器自动打开,并使用我自己的帐户 (email2@gmail.com) 自动登录,并要求我允许我的程序访问日历 API。

我接受了。

这个弹出窗口再也没有出现过。

对任何帐户所做的任何更改都是在我自己的日历上完成的,而不是 JSON 文件引用的那个。

怎么了?如何使用独特的程序访问多个 Google 帐户?

这个程序将作为计划任务在服务器上运行,我不能打开任何窗口,因为没有人会看服务器的屏幕。由于没有用户,我无法要求用户进行身份验证。

但我可以对任何用户的 Google 帐户执行任何操作(启用 API、创建密钥、授予应用程序等)

【问题讨论】:

    标签: calendar google-api-dotnet-client


    【解决方案1】:

    您应该为每个用户创建一个新的 CalendarService(轻量级组件)。 CalendarService 和所有其他 Google 服务都实现为不可变对象(为了简单起见并支持线程安全操作)。

    为每个用户创建一个新服务,并使用不同的 userId(“user1”、“user2”等)作为 GoogleWebAuthorizationBroker.AuthorizeAsync 的参数。

    更新:

    您还应该创建自己的流类:

    class ForceUIGoogleAuthorizationCodeFlow : AuthorizationCodeFlow
    {
        public override AuthorizationCodeRequestUrl CreateAuthorizationCodeRequest(string redirectUri)
        {
            return new GoogleAuthorizationCodeRequestUrl(new Uri(AuthorizationServerUrl))
            {
                ClientId = ClientSecrets.ClientId,
                Scope = string.Join(" ", Scopes),
                RedirectUri = redirectUri,
                ApprovalPrompt = "force",
            };
        }
    }
    

    然后,

    将您对 GoogleWebAuthorizationBroker 的调用替换为以下代码:

    var initializer = new GoogleAuthorizationCodeFlow.Initializer
    {
           ClientSecrets = clientSecrets,
           Scopes = [SCOPED_HERE];
           initializer.DataStore = new FileDataStore("Credentials");
    };
    var flow = new ForceUIGoogleAuthorizationCodeFlow(initializer);
    
    // Create authorization code installed app instance and authorize the user.
    crdentials = await new AuthorizationCodeInstalledApp(flow, 
          new LocalServerCodeReceiver()).AuthorizeAsync
          ("USER_ID_HERE", taskCancellationToken).ConfigureAwait(false);
    

    【讨论】:

    • 你好。据我所知,这就是我所做的:我有一个带有 Load 方法的类“GoogleExtractor”(类似于上面的源)。接下来,我有另一个类在循环中实例化 GoogleExtractor 对象,每个用户一个。我试图通过用户登录名(GMail 地址)在 GoogleWebAuthorizationBroker.AuthorizeAsync() 调用中替换“用户”常量,但它没有改变任何内容:我总是在我的 Google Chrome 关联的 Google 帐户上连接,即使这个帐户不应该被我的程序调用。
    • @StringBuilder,最好在不需要任何api密钥生成的地方使用谷歌客户端sdk。
    • 对我使用 GoogleWebAuthorizationBroker 没有任何不同。问题是,一旦我在浏览器中登录 Google,即使指定了不同的用户 ID/电子邮件,浏览器也只会显示我自己帐户的同意屏幕。没有提示指定帐户。对于日历,唯一的解决方案似乎是使用服务帐户并与服务帐户共享日历(公平地说,这是 Google 推荐的)
    • 更新 - 扩展最后一条评论。如果我将 GoogleAuthorizationCodeRequestUrl 中的 LoginHint 设置为电子邮件,那么它会有所帮助,但它不会强制它发送给该电子邮件。然后用户可以输入他们喜欢的任何内容。如果他们有一个现有帐户登录,他们可以单击该帐户。就我而言,这个问题是我可以看到它会引起一些用户的困惑。更糟糕的是,如果用户电子邮件无效/未在 Google 上注册,它将只使用当前经过身份验证的用户。
    猜你喜欢
    • 2015-05-12
    • 2017-03-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-30
    相关资源
    最近更新 更多