Calendar .NET谷歌日历API v3:多帐户身份验证
我正在尝试编写一个程序,它将在CRM和几个Google帐户的Google日历之间同步事件 这是一个Windows控制台应用程序 对于每个Google帐户,我在API控制台中启用了日历API,创建了一个名为“UpdateSync”(type:native)的应用程序,然后下载了JSON文件 我使用帐户邮件地址(即email1@gmail.com.json) 接下来,我编写了下面的代码:Calendar .NET谷歌日历API v3:多帐户身份验证,calendar,google-api-dotnet-client,Calendar,Google Api Dotnet Client,我正在尝试编写一个程序,它将在CRM和几个Google帐户的Google日历之间同步事件 这是一个Windows控制台应用程序 对于每个Google帐户,我在API控制台中启用了日历API,创建了一个名为“UpdateSync”(type:native)的应用程序,然后下载了JSON文件 我使用帐户邮件地址(即email1@gmail.com.json) 接下来,我编写了下面的代码: /// <summary> /// Loads updated event from
/// <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;
}
// [...]
}
//
///在上次同步日期后从Google日历加载更新的事件
///
///我们希望获得约会的用户
公共列表加载约会(用户)
{
Console.WriteLine(“LoadAppointments({0})”,user.Email;
列表约会=新列表();
用户凭证;
使用(var stream=newfilestream(string.Format(“credentials\\{0}.json”、user.Email)、FileMode.Open、FileAccess.Read))
{
尝试
{
credential=GoogleWebAuthorizationBroker.AuthorizationAsync(GoogleClientSecrets.Load(stream).Secrets,新[]{CalendarService.Scope.Calendar},“用户”,CancellationToken.None,新文件数据存储(“UpdayesSync.Credentials”)。结果;
}
捕获(例外e)
{
控制台写入线(e.Message);
返回null;
}
}
BaseClientService.Initializer Initializer=新的BaseClientService.Initializer();
initializer.HttpClientInitializer=凭证;
initializer.ApplicationName=“UpdateSync”;
服务=新日历服务(初始值设定项);
EventsResource.ListRequest req=service.Events.List(“主”);
req.TimeMin=DateTime.Now.AddMonths(-2).ToString(“o”);
req.showdeled=true;
req.updateMin=XmlConvert.ToString(LastSync,XmlDateTimeSerializationMode.Utc);
req.SingleEvents=true;
事件;
尝试
{
events=req.Execute();
}
捕获(例外e)
{
控制台写入线(e.Message);
返回null;
}
// [...]
}
这段代码是为每个JSON文件调用的
第一次调用时,要同步的帐户为“email1@gmail.com".
Google Chrome自动关闭,并使用我自己的帐户自动登录(email2@gmail.com)并要求我允许我的程序访问日历API
我接受了
此弹出窗口不再显示
对任何帐户所做的任何更改都是在我自己的日历上完成的,而不是JSON文件所指的日历
怎么了?如何使用一个独特的程序访问多个Google帐户
这个程序将作为计划任务在服务器上运行,我不能打开任何窗口,因为没有人会查看服务器的屏幕。我不能要求用户对自己进行身份验证,因为没有用户
但是我可以在任何用户的Google帐户上做任何事情(启用API、创建密钥、授予应用程序等)您应该为每个用户创建一个新的CalendarService(轻量级组件)。CalendarService和所有其他Google服务都实现为不可变的(为了简单和支持线程安全操作) 为每个用户创建一个新服务,并使用不同的userId(“user1”、“user2”等)作为GoogleWebAuthorizationBroker.AuthorizationAsync的参数 更新: 您还应该创建自己的流类: 然后呢, 将您对GoogleWebAuthorizationBroker的调用替换为以下代码:
你好据我所知,我就是这么做的:我有一个类“GoogleExtractor”,带有一个Load方法(源代码类似于上面的一个)。接下来,我有另一个类在循环中实例化GoogleExtractor对象,每个用户一个。我试图通过用户登录(GMail地址)在GoogleWebAuthorizationBroker.AuthorizationAsync()调用中删除“user”常量,但它没有改变任何东西:我总是在与我的Google Chrome关联的Google帐户上连接,即使我的程序不应该调用此帐户。@StringBuilder,在不需要任何api密钥生成的情况下,最好使用Google客户端sdk。对我来说,使用GoogleWebAuthorizationBroker与使用GoogleWebAuthorizationBroker没有任何不同。问题是,一旦我在浏览器中登录谷歌,即使指定了不同的用户ID/电子邮件,浏览器也只会显示我自己帐户的同意屏幕。没有提示指定的帐户。对于日历,唯一的解决方案似乎是使用服务帐户并与服务帐户共享日历(公平地说,这是谷歌建议的)更新-在最后的评论上展开。如果我在GoogleAuthorizationCodeRequestUrl中将LoginHint设置为电子邮件,那么它会有所帮助,但不会强制将其设置为该电子邮件。然后用户可以输入他们喜欢的任何内容。如果他们有一个已登录的现有帐户,他们可以单击该帐户。在我的例子中,这个问题是我可以看到它会引起一些用户的困惑。但更糟糕的是,如果用户电子邮件无效/未在Google上注册,它将只使用当前经过身份验证的用户。
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",
};
}
}
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);