Google 日历 API 使用服务帐户或 Web 应用程序 ID 的 v3 .NET 身份验证
Google Calendar API v3 .NET authentication with Service Account or Web Application ID
我需要在我的 .NET 4.5 应用程序(VS 2013 项目)上连接一个 Google 日历。
我想从日历中获取所有信息,例如:事件、日期、注释、姓名、客人等...
我使用 Google 开发人员控制台创建了一个 Web 应用程序客户端 ID 和一个 服务帐户 ,但是我得到不同的错误,没有结果。
我实现了 2 种不同的方法,一种使用 Web 应用程序客户端 ID 登录,一种使用服务帐户。
这是普通的 ASPX 页面
public partial class Calendar : System.Web.UI.Page
{
// client_secrets.json path.
private readonly string GoogleOAuth2JsonPath = ConfigurationManager.AppSettings["GoogleOAuth2JsonPath"];
// p12 certificate path.
private readonly string GoogleOAuth2CertificatePath = ConfigurationManager.AppSettings["GoogleOAuth2CertificatePath"];
// @developer... e-mail address.
private readonly string GoogleOAuth2EmailAddress = ConfigurationManager.AppSettings["GoogleOAuth2EmailAddress"];
// certificate password ("notasecret").
private readonly string GoogleOAuth2PrivateKey = ConfigurationManager.AppSettings["GoogleOAuth2PrivateKey"];
// my Google account e-mail address.
private readonly string GoogleAccount = ConfigurationManager.AppSettings["GoogleAccount"];
protected void Page_Load(object sender, EventArgs e)
{
// Enabled one at a time to test
//GoogleLoginWithServiceAccount();
GoogleLoginWithWebApplicationClientId();
}
}
使用 Web 应用程序客户端 ID
我已尝试为 JSON 配置文件配置重定向 URI 参数,但似乎没有任何 URI 起作用。我在开发环境中,所以我在端口 44300(启用 SSL)上使用 IIS Express。我得到的错误是:
Error: redirect_uri_mismatch
Application: CalendarTest
The redirect URI in the request: http://localhost:56549/authorize/ did not match a registered redirect URI.
Request details
scope=https://www.googleapis.com/auth/calendar
response_type=code
redirect_uri=http://localhost:56549/authorize/
access_type=offline
client_id=....apps.googleusercontent
代码
private void GoogleLoginWithWebApplicationClientId()
{
UserCredential credential;
// This example uses the client_secrets.json file for authorization.
// This file can be downloaded from the Google Developers Console
// project.
using (FileStream json = new FileStream(Server.MapPath(GoogleOAuth2JsonPath), FileMode.Open,
FileAccess.Read))
{
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(json).Secrets,
new[] { CalendarService.Scope.Calendar },
"...@developer.gserviceaccount.com", CancellationToken.None,
new FileDataStore("Calendar.Auth.Store")).Result;
}
// Create the service.
CalendarService service = new CalendarService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "CalendarTest"
});
try
{
CalendarListResource.ListRequest listRequest = service.CalendarList.List();
IList<CalendarListEntry> calendarList = listRequest.Execute().Items;
foreach (CalendarListEntry entry in calendarList)
{
txtCalendarList.Text += "[" + entry.Summary + ". Location: " + entry.Location + ", TimeZone: " +
entry.TimeZone + "] ";
}
}
catch (TokenResponseException tre)
{
txtCalendarList.Text = tre.Message;
}
}
使用服务帐户(首选)
我可以到达 CalendarListResource.ListRequest listRequest = service.CalendarList.List();
行,所以我猜登录有效,但是,当我想要 IList<CalendarListEntry> calendarList = listRequest.Execute().Items;
上的列表时,我收到以下错误:
Error:"unauthorized_client", Description:"Unauthorized client or scope in request.", Uri:""
代码
private void GoogleLoginWithServiceAccount()
{
/*
* From https://developers.google.com/console/help/new/?hl=en_US#generatingoauth2:
* The name of the downloaded private key is the key's thumbprint. When inspecting the key on your computer, or using the key in your application,
* you need to provide the password "notasecret".
* Note that while the password for all Google-issued private keys is the same (notasecret), each key is cryptographically unique.
* GoogleOAuth2PrivateKey = "notasecret".
*/
X509Certificate2 certificate = new X509Certificate2(Server.MapPath(GoogleOAuth2CertificatePath),
GoogleOAuth2PrivateKey, X509KeyStorageFlags.Exportable);
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(GoogleOAuth2EmailAddress)
{
User = GoogleAccount,
Scopes = new[] { CalendarService.Scope.Calendar }
}.FromCertificate(certificate));
// Create the service.
CalendarService service = new CalendarService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "CalendarTest"
});
try
{
CalendarListResource.ListRequest listRequest = service.CalendarList.List();
IList<CalendarListEntry> calendarList = listRequest.Execute().Items;
foreach (CalendarListEntry entry in calendarList)
{
txtCalendarList.Text += "[" + entry.Summary + ". Location: " + entry.Location + ", TimeZone: " +
entry.TimeZone + "] ";
}
}
catch (TokenResponseException tre)
{
txtCalendarList.Text = tre.Message;
}
}
我更喜欢服务帐户登录,因为用户不需要在同意屏幕上登录,因为应用程序应该在每次需要刷新时自行完成。是否可以使用带有免费 Google 帐户的服务帐户,或者我是否需要管理控制台?我读过很多关于此的相互矛盾的报道...
无论如何,用 Google 和 Whosebug 环顾四周,我没有找到解决方案。我已经看到并尝试了许多问题和解决方案,但没有结果。一些例子:
- Keep getting Error: redirect_uri_mismatch using youtube api v3
- Google API Calender v3 Event Insert via Service Account using Asp.Net MVC
- https://developers.google.com/google-apps/calendar/instantiate
- https://groups.google.com/forum/#!topic/google-calendar-api/MySzyAXq12Q
请帮忙! :-)
更新 1 - 使用服务帐户(首选) - 已解决!
我的代码中唯一的问题是:
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(GoogleOAuth2EmailAddress)
{
//User = GoogleAccount,
Scopes = new[] { CalendarService.Scope.Calendar }
}.FromCertificate(certificate));
不需要 User = GoogleAccount
.
您的身份验证肯定有问题。这是我的服务帐户身份验证方法的副本。
/// <summary>
/// Authenticating to Google using a Service account
/// Documentation: https://developers.google.com/accounts/docs/OAuth2#serviceaccount
/// </summary>
/// <param name="serviceAccountEmail">From Google Developer console https://console.developers.google.com</param>
/// <param name="keyFilePath">Location of the Service account key file downloaded from Google Developer console https://console.developers.google.com</param>
/// <returns></returns>
public static CalendarService AuthenticateServiceAccount(string serviceAccountEmail, string keyFilePath)
{
// check the file exists
if (!File.Exists(keyFilePath))
{
Console.WriteLine("An Error occurred - Key file does not exist");
return null;
}
string[] scopes = new string[] {
CalendarService.Scope.Calendar , // Manage your calendars
CalendarService.Scope.CalendarReadonly // View your Calendars
};
var certificate = new X509Certificate2(keyFilePath, "notasecret", X509KeyStorageFlags.Exportable);
try
{
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
Scopes = scopes
}.FromCertificate(certificate));
// Create the service.
CalendarService service = new CalendarService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "Calendar API Sample",
});
return service;
}
catch (Exception ex)
{
Console.WriteLine(ex.InnerException);
return null;
}
}
我也有一个教程。我的教程 Google Calendar API Authentication with C# The code above was ripped directly from my sample project Google-Dotnet-Samples project GitHub
Note/headsup: 请记住,服务帐户不是您。它现在有任何日历,当您开始时,您需要创建一个日历并将其插入到日历列表中,然后才能返回任何结果。此外,您将无法通过 Google 日历的网络版本查看此日历,因为您无法作为服务帐户登录。最好的解决方法是让服务帐户授予您对日历的权限。
我需要在我的 .NET 4.5 应用程序(VS 2013 项目)上连接一个 Google 日历。 我想从日历中获取所有信息,例如:事件、日期、注释、姓名、客人等...
我使用 Google 开发人员控制台创建了一个 Web 应用程序客户端 ID 和一个 服务帐户 ,但是我得到不同的错误,没有结果。 我实现了 2 种不同的方法,一种使用 Web 应用程序客户端 ID 登录,一种使用服务帐户。
这是普通的 ASPX 页面
public partial class Calendar : System.Web.UI.Page
{
// client_secrets.json path.
private readonly string GoogleOAuth2JsonPath = ConfigurationManager.AppSettings["GoogleOAuth2JsonPath"];
// p12 certificate path.
private readonly string GoogleOAuth2CertificatePath = ConfigurationManager.AppSettings["GoogleOAuth2CertificatePath"];
// @developer... e-mail address.
private readonly string GoogleOAuth2EmailAddress = ConfigurationManager.AppSettings["GoogleOAuth2EmailAddress"];
// certificate password ("notasecret").
private readonly string GoogleOAuth2PrivateKey = ConfigurationManager.AppSettings["GoogleOAuth2PrivateKey"];
// my Google account e-mail address.
private readonly string GoogleAccount = ConfigurationManager.AppSettings["GoogleAccount"];
protected void Page_Load(object sender, EventArgs e)
{
// Enabled one at a time to test
//GoogleLoginWithServiceAccount();
GoogleLoginWithWebApplicationClientId();
}
}
使用 Web 应用程序客户端 ID
我已尝试为 JSON 配置文件配置重定向 URI 参数,但似乎没有任何 URI 起作用。我在开发环境中,所以我在端口 44300(启用 SSL)上使用 IIS Express。我得到的错误是:
Error: redirect_uri_mismatch
Application: CalendarTest
The redirect URI in the request: http://localhost:56549/authorize/ did not match a registered redirect URI.
Request details
scope=https://www.googleapis.com/auth/calendar
response_type=code
redirect_uri=http://localhost:56549/authorize/
access_type=offline
client_id=....apps.googleusercontent
代码
private void GoogleLoginWithWebApplicationClientId()
{
UserCredential credential;
// This example uses the client_secrets.json file for authorization.
// This file can be downloaded from the Google Developers Console
// project.
using (FileStream json = new FileStream(Server.MapPath(GoogleOAuth2JsonPath), FileMode.Open,
FileAccess.Read))
{
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(json).Secrets,
new[] { CalendarService.Scope.Calendar },
"...@developer.gserviceaccount.com", CancellationToken.None,
new FileDataStore("Calendar.Auth.Store")).Result;
}
// Create the service.
CalendarService service = new CalendarService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "CalendarTest"
});
try
{
CalendarListResource.ListRequest listRequest = service.CalendarList.List();
IList<CalendarListEntry> calendarList = listRequest.Execute().Items;
foreach (CalendarListEntry entry in calendarList)
{
txtCalendarList.Text += "[" + entry.Summary + ". Location: " + entry.Location + ", TimeZone: " +
entry.TimeZone + "] ";
}
}
catch (TokenResponseException tre)
{
txtCalendarList.Text = tre.Message;
}
}
使用服务帐户(首选)
我可以到达 CalendarListResource.ListRequest listRequest = service.CalendarList.List();
行,所以我猜登录有效,但是,当我想要 IList<CalendarListEntry> calendarList = listRequest.Execute().Items;
上的列表时,我收到以下错误:
Error:"unauthorized_client", Description:"Unauthorized client or scope in request.", Uri:""
代码
private void GoogleLoginWithServiceAccount()
{
/*
* From https://developers.google.com/console/help/new/?hl=en_US#generatingoauth2:
* The name of the downloaded private key is the key's thumbprint. When inspecting the key on your computer, or using the key in your application,
* you need to provide the password "notasecret".
* Note that while the password for all Google-issued private keys is the same (notasecret), each key is cryptographically unique.
* GoogleOAuth2PrivateKey = "notasecret".
*/
X509Certificate2 certificate = new X509Certificate2(Server.MapPath(GoogleOAuth2CertificatePath),
GoogleOAuth2PrivateKey, X509KeyStorageFlags.Exportable);
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(GoogleOAuth2EmailAddress)
{
User = GoogleAccount,
Scopes = new[] { CalendarService.Scope.Calendar }
}.FromCertificate(certificate));
// Create the service.
CalendarService service = new CalendarService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "CalendarTest"
});
try
{
CalendarListResource.ListRequest listRequest = service.CalendarList.List();
IList<CalendarListEntry> calendarList = listRequest.Execute().Items;
foreach (CalendarListEntry entry in calendarList)
{
txtCalendarList.Text += "[" + entry.Summary + ". Location: " + entry.Location + ", TimeZone: " +
entry.TimeZone + "] ";
}
}
catch (TokenResponseException tre)
{
txtCalendarList.Text = tre.Message;
}
}
我更喜欢服务帐户登录,因为用户不需要在同意屏幕上登录,因为应用程序应该在每次需要刷新时自行完成。是否可以使用带有免费 Google 帐户的服务帐户,或者我是否需要管理控制台?我读过很多关于此的相互矛盾的报道...
无论如何,用 Google 和 Whosebug 环顾四周,我没有找到解决方案。我已经看到并尝试了许多问题和解决方案,但没有结果。一些例子:
- Keep getting Error: redirect_uri_mismatch using youtube api v3
- Google API Calender v3 Event Insert via Service Account using Asp.Net MVC
- https://developers.google.com/google-apps/calendar/instantiate
- https://groups.google.com/forum/#!topic/google-calendar-api/MySzyAXq12Q
请帮忙! :-)
更新 1 - 使用服务帐户(首选) - 已解决!
我的代码中唯一的问题是:
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(GoogleOAuth2EmailAddress)
{
//User = GoogleAccount,
Scopes = new[] { CalendarService.Scope.Calendar }
}.FromCertificate(certificate));
不需要 User = GoogleAccount
.
您的身份验证肯定有问题。这是我的服务帐户身份验证方法的副本。
/// <summary>
/// Authenticating to Google using a Service account
/// Documentation: https://developers.google.com/accounts/docs/OAuth2#serviceaccount
/// </summary>
/// <param name="serviceAccountEmail">From Google Developer console https://console.developers.google.com</param>
/// <param name="keyFilePath">Location of the Service account key file downloaded from Google Developer console https://console.developers.google.com</param>
/// <returns></returns>
public static CalendarService AuthenticateServiceAccount(string serviceAccountEmail, string keyFilePath)
{
// check the file exists
if (!File.Exists(keyFilePath))
{
Console.WriteLine("An Error occurred - Key file does not exist");
return null;
}
string[] scopes = new string[] {
CalendarService.Scope.Calendar , // Manage your calendars
CalendarService.Scope.CalendarReadonly // View your Calendars
};
var certificate = new X509Certificate2(keyFilePath, "notasecret", X509KeyStorageFlags.Exportable);
try
{
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
Scopes = scopes
}.FromCertificate(certificate));
// Create the service.
CalendarService service = new CalendarService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "Calendar API Sample",
});
return service;
}
catch (Exception ex)
{
Console.WriteLine(ex.InnerException);
return null;
}
}
我也有一个教程。我的教程 Google Calendar API Authentication with C# The code above was ripped directly from my sample project Google-Dotnet-Samples project GitHub
Note/headsup: 请记住,服务帐户不是您。它现在有任何日历,当您开始时,您需要创建一个日历并将其插入到日历列表中,然后才能返回任何结果。此外,您将无法通过 Google 日历的网络版本查看此日历,因为您无法作为服务帐户登录。最好的解决方法是让服务帐户授予您对日历的权限。