如何使用访问令牌获取 Google 日历事件

Posted

技术标签:

【中文标题】如何使用访问令牌获取 Google 日历事件【英文标题】:How to get Google-Calendar events using access token 【发布时间】:2021-12-13 07:36:58 【问题描述】:

我已经构建了一个 django 应用程序,其中包括 google Oauth2.0 登录。 我想在每个用户使用 Oauth2.0 登录时获取他们的谷歌日历事件,我编写了以下代码。我将访问令牌保存到 UserAuth 表中并获取它,然后用它来获取谷歌日历。

def get_events_server(request):
    user = User.objects.get(username=request.user)
    creds = UserAuth.objects.get(user=user).google_id_token

    credentials = AccessTokenCredentials(creds, "")
    http = httplib2.Http()
    http = credentials.authorize(http)

    service = build('calendar', 'v3', http=http)
    return service

当我运行代码时,发生了以下错误。

HttpError at /calendar/
<HttpError 403 when requesting https://www.googleapis.com/calendar/v3/calendars/primary/events?timeMin=2021-10-28T04%3A33%3A08.956703Z&timeMax=2021-11-04T04%3A33%3A08.956712Z&singleEvents=true&timeZone=GMT%2B9%3A00&orderBy=startTime&alt=json returned "Request had insufficient authentication scopes.". Details: "['message': 'Insufficient Permission', 'domain': 'global', 'reason': 'insufficientPermissions']">

有没有办法跳过这个问题?

【问题讨论】:

您能否提供更多有关您如何获得访问令牌的信息?为了获得它们,用户是否以自己的身份进行身份验证?如果您通过身份验证获得它,则访问令牌将只能访问您的帐户可以访问的事件。 是的,用户将使用他们的谷歌帐户登录,如 Oauth 登录,他们将获取他们的访问令牌。 【参考方案1】:

你可以运行下面的代码。

def get_events_server(request):

    SCOPES = ['https://www.googleapis.com/auth/calendar']
    user = User.objects.get(username=request.user)
    authuser = UserAuth.objects.get(user=user)
    google_permission = authuser.google_permission
    print(google_permission)
    creds = None
    if google_permission == True:
        token_id = authuser.google_id_token
        creds = Credentials(token_id, refresh_token=None, id_token=None, token_uri=None, client_id=None, client_secret=None, scopes=SCOPES, default_scopes=None, quota_project_id=None, expiry=None, rapt_token=None)    
    else:
        if creds and creds.expired and creds.refresh_token:
            creds.refresh(Request())
            print("creds")
        else:            
            CLIENT_SECRET_FILE =  os.path.join(settings.BASE_DIR, '../key/client_secret_key.json')            
            flow = InstalledAppFlow.from_client_secrets_file(
                CLIENT_SECRET_FILE, SCOPES)
            
            #credentials = service_account.Credentials.from_service_account_file(CLIENT_SECRET_FILE)
            #creds = tools.run_flow(flow, store)
            flow.redirect_uri = 'https://google-oauth-django.herokuapp.com/calendar/'
            flow.run_local_server(port=8080,open_browser=True)
            creds = flow.credentials
            print(creds.token)
            authuser.google_permission = True
            authuser.save()
    
    service = build('calendar', 'v3', credentials=creds)
    return service

这对我来说效果很好。

【讨论】:

你能把结果显示为截图吗?【参考方案2】:

您在这里有点困惑,让我们先看看身份验证和授权之间的区别。

身份验证或 Open Id 连接正在登录,您让用户登录到他们的 google 帐户,您会得到一个 id 令牌,并且您可以访问他们的个人资料信息,因为用户已登录。您正在验证背后的用户机器拥有该帐户。在您的代码中查看您正在使用的 id_token 打开 id 连接以验证用户。

creds = UserAuth.objects.get(user=user).google_id_token

为了访问用户的私人数据,您的应用程序需要被授权访问该数据。授权由范围或您需要的访问范围定义。为了使用谷歌日历 API,您需要一个访问令牌,其范围将授予您访问用户谷歌日历事件的权限

您应该查看Python quickstart for google calendar,它将向您展示如何使用 Oauth2 让您的应用程序请求用户授权以访问他们的谷歌日历数据。

def main():
    """Shows basic usage of the Google Calendar API.
    Prints the start and name of the next 10 events on the user's calendar.
    """
    creds = None
    # The file token.json stores the user's access and refresh tokens, and is
    # created automatically when the authorization flow completes for the first
    # time.
    if os.path.exists('token.json'):
        creds = Credentials.from_authorized_user_file('token.json', SCOPES)
    # If there are no (valid) credentials available, let the user log in.
    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
            creds.refresh(Request())
        else:
            flow = InstalledAppFlow.from_client_secrets_file(
                'credentials.json', SCOPES)
            creds = flow.run_local_server(port=0)
        # Save the credentials for the next run
        with open('token.json', 'w') as token:
            token.write(creds.to_json())

    service = build('calendar', 'v3', credentials=creds)

    # Call the Calendar API
    now = datetime.datetime.utcnow().isoformat() + 'Z' # 'Z' indicates UTC time
    print('Getting the upcoming 10 events')
    events_result = service.events().list(calendarId='primary', timeMin=now,
                                        maxResults=10, singleEvents=True,
                                        orderBy='startTime').execute()
    events = events_result.get('items', [])

来自 cmets

您的链接同意屏幕请求返回错误。这是重定向 uri 未匹配错误,它是您在设置 oauth2 时可能遇到的最常见错误之一。

如果您检查错误,它会告诉您此 url redirect_uri: http://localhost:61668/ 存在问题,您正在从该 url 发送您的请求。这意味着您需要转到谷歌云控制台并将该重定向 uri 添加到您接受的重定向 uri 列表中。请记住,它必须完全匹配,因此必须包含端口号和尾部斜杠。

这些是您当前需要添加的重定向 uri http://localhost:61668/

尝试设置

flow.run_local_server(port=0)

flow.run_local_server(port=8000)

然后添加

http://localhost:8000/

作为您的重定向 uri。

如果您不知道该视频将如何向您展示如何解决它。 Google OAuth2: How the fix redirect_uri_mismatch error. Part 2 server sided web applications.

【讨论】:

我不确定应该从哪里获得 token.json 和 credentials.json?这个文件是我的访问令牌或用户令牌的信息吗? @DaimTo credentials.json 会在您在 Google Developer Console 上注册时在您的项目中创建。只需记住在 library 下启用 Google Calendar api。 token.json 是在用户第一次运行我们的应用程序时创建的,他们的凭据刷新令牌和访问令牌将存储在该文件中。我建议你按照它解释如何创建它们的快速入门。 我只是按照您的代码运行它,在这种情况下出现以下错误:请访问此 URL 以授权此应用程序:accounts.google.com/o/oauth2/… 检查我的更新。 我添加了redirect_uri,但出现了同样的错误。 @DalmTo

以上是关于如何使用访问令牌获取 Google 日历事件的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 JavaScript 从 Google 日历页面获取事件 ID?

如何让服务器访问Google Calendar API?

如何使用 Google Refresh Token 更新 Google Access Token

即使似乎授予访问权限,Google Calendar API在OAuth期间也会出现403错误

如何在 Google 日历 API v3 中获取特定日期的日历数据?

如何检索 Google 日历活动的扩展属性?