带有服务帐户的 Google Calendar Python API 未返回任何结果
Posted
技术标签:
【中文标题】带有服务帐户的 Google Calendar Python API 未返回任何结果【英文标题】:Google Calendar Python API with service account returning no results 【发布时间】:2014-09-01 11:36:27 【问题描述】:我正在尝试下载我的用户可以看到的 Google 日历列表。我已经设置了一个服务帐户,并且我有这个代码(它适用于 Analytics API 的不同帐户):
from apiclient.discovery import build
from oauth2client.client import SignedJwtAssertionCredentials
import pprint
def prepare_credentials():
f = file(keyFilePath, 'rb')
key = f.read()
f.close()
credentials = SignedJwtAssertionCredentials(
service_account_email_address, key,
scope='https://www.googleapis.com/auth/calendar.readonly')
return credentials
http = httplib2.Http()
credentials = prepare_credentials()
http = credentials.authorize(http)
service = build('calendar', 'v3', http=http)
httpRequest = service.calendarList().list()
data = httpRequest.execute()
pprint.pprint(data)
结果:
u'etag': u'"YXs7dfDSFSFD9F0k/sofIhuT4dSLyxKaRH7vNpx5BOEU"',
u'items': [],
u'kind': u'calendar#calendarList',
u'nextSyncToken': u'00001405024697194000'
问题是,我知道我可以访问日历,而且我什至使用过“试试看!”本页部分:https://developers.google.com/google-apps/calendar/v3/reference/calendarList/list,返回预期结果,约10个日历。我尝试了不同版本的范围参数('https://www.googleapis.com/auth/calendar.readonly',和 ['https://www.googleapis.com/auth/calendar','https://www.googleapis.com/auth/calendar.readonly']),我还尝试将我自己的电子邮件地址添加为“prn”和“子”参数,所有这些都给我“拒绝访问”错误。我不知道为什么我可以使用我的服务帐户获得授权,但是当这些结果可以通过不同的身份验证方法清楚地查看时,我无法实际查看结果。
我做错了什么?
【问题讨论】:
【参考方案1】:只是想用我最终使用的解决方案来更新这个问题。
如果您希望服务帐户能够在日历上拥有所有者权限,似乎唯一的方法就是使用 API 创建辅助日历作为服务帐户进行身份验证时 (https://developers.google.com/google-apps/calendar/v3/reference/calendars/insert)。服务帐户没有任何它是其所有者的主日历,但它将是新的辅助日历的所有者。
然后,您可以使用访问控制规则 API 端点 (https://developers.google.com/google-apps/calendar/v3/reference/acl/insert) 与您自己的 Google 帐户(或任何可以登录以在浏览器中查看日历的非服务帐户)共享此日历。新用户也可以设置为所有者。
编辑:下面的解决方案不准确。
这不是问题,但我在任何地方都找不到它,我认为人们可能想知道,所以我也将在这里回答:
如果您希望与会者在您插入或更新活动时收到电子邮件通知,您需要做的不仅仅是将“sendNotifications”参数设置为 True。与该用户共享日历后,该用户还需要进入您服务帐户日历的“日历设置”,并在“提醒和通知”选项卡中激活电子邮件通知。
编辑:这是不准确的。任何更改设置以在此日历上接收通知的人都会收到通知,无论他们是否被邀请参加活动。我还没有找到通过 API 邀请人们参加活动的方法服务帐户,并且只有受邀者会收到邀请电子邮件。我会在 *** 上问另一个问题。
【讨论】:
【参考方案2】:只有在使用该用户的凭据执行呼叫时,才能看到特定用户的日历列表。服务帐户将始终为您提供属于该服务帐户的日历列表。如果您想访问您的日历列表,我建议您使用 Oauth2 令牌作为您的帐户。
【讨论】:
使用 OAuth 的问题在于,我相信夜间脚本无法在我不在时访问日历,除非我遗漏了什么。我需要一个 Python 脚本,以便能够在一夜之间访问和更改这些数据,而无需用户干预。 我是个白痴,与我的服务帐户共享日历完全有效!谢谢!! 看来我只能授予它读取权限。您是否知道一种方法也可以授予服务帐户写入权限? 有刷新 Oauth 令牌,允许在用户不在线时检索凭据(在第一次令牌交换时,您会获得访问令牌和刷新令牌,然后您可以使用它们来获得更多访问权限令牌)。通常,您应该能够向服务帐户授予所有权限,除非您的帐户位于已限制最大权限的域中。 关于令牌的更多细节在这里:developers.google.com/accounts/docs/OAuth2WebServer#refresh 请注意,您需要使 access_type 离线才能获得刷新令牌。【参考方案3】:经过一番挖掘,您可以允许域外的用户(api 服务帐户)访问谷歌日历。
检查以下设置:Google Admin、Google Apps、日历、共享设置 并选择以下选项之一:
( ) Only free/busy information (hide event details) Default
( ) Share all information, but outsiders cannot change calendars
(X) Share all information, and outsiders can change calendars
( ) Share all information, and allow managing of calendars
然后您可以在Share with specific people
下的各个日历共享设置中将您的日历共享到api服务中
这对某人有什么帮助。
【讨论】:
【参考方案4】:最初,我自己也在为此苦苦挣扎。但我认为我已经取得了足够的进展,可以提供一些帮助。
看起来每个服务帐户都分配了一个唯一的“client_email”。此值是包含在可下载 JSON 文件中的字段,来自项目的 API -> Credentials 部分。格式类似于 xxxxx-yyyyy@developer.gserviceaccount.com。在上面的代码中,您似乎通过“service_account_email_address”变量引用了这个值。
由于 client_email 地址与您的个人电子邮件地址不同,因此您引用的主日历和辅助日历不是一回事。默认情况下,我认为服务帐户电子邮件没有与之关联的任何日历,这就是您在结果中看不到任何日历的原因。当您添加两个日历然后使用 calendarList.list() 方法时,这一点变得很明显。但在添加任何日历之前,您必须将范围从只读更改为读/写。您可以通过将代码更改为:
## Original Scope needs to be changed...
#scope='https://www.googleapis.com/auth/calendar.readonly'
## Must allow the ability to write to calendars...
scope='https://www.googleapis.com/auth/calendar'
一旦您允许读/写,您可以添加两个日历,然后通过执行以下操作列出它们:
def createCalendar(): ## Create the calendar...
calendar =
'summary': 'Calendar used to communicate lease end dates.',
'timeZone': 'America/Los_Angeles'
created_calendar = service.calendars().insert(body=calendar).execute()
print "Created Calendar ID: ", created_calendar['id']
## In main block of code, call the createCalendar() twice...
createCalendar()
createCalendar()
## Show the current list of calendars (should have 2 listed)...
httpRequest = service.calendarList().list()
data = httpRequest.execute()
pprint.pprint(data)
创建日历后,再次尝试运行您的代码,您现在应该会在“数据”结果中看到列出的两个新日历。但是,这两个日历仍然只与服务帐户相关联。因此,如果您登录个人电子邮件 (myEmail@gmail.com),这些日历将不会显示在您的个人资料 (http://calendar.google.com) 中。
要让它们显示在您的个人日历列表中,您必须授予您的个人电子邮件地址查看和/或修改日历的权限。为此,您必须插入一个 ACL,为您的个人电子邮件 (myEmail@gmail.com) 提供适当的权限。
但是,如果您尝试采取其他方式(允许服务帐户访问您的个人日历)。您必须登录您的个人电子邮件帐户 (myEmail@gmail.com),与服务帐户 client_email 共享特定日历,并分配适当的权限级别(进行更改和管理共享等)。与服务帐户共享日历后,日历将列在您的 calendarList().list() 结果中,您应该能够按预期查看事件。
【讨论】:
查看各个日历事件时,必须指定要使用的 calendarId。默认情况下,它使用不正确的“主要”。eventsResult = service.events().list(calendarId=gCalendarId, singleEvents=True, orderBy='startTime').execute() events = eventsResult.get('items', [])
以上是关于带有服务帐户的 Google Calendar Python API 未返回任何结果的主要内容,如果未能解决你的问题,请参考以下文章
使用服务帐户身份验证访问 Google Calendar API
从google-calendar-API获取详细信息,无需帐户关联
G Suite帐户在Calendar API中缺少displayName参数