首页 > 解决方案 > 将 Python 脚本从 oauth2client 升级到 google-auth

问题描述

我想将以下代码从oauth2client升级到google-auth。是的,这段代码确实有效,是他们网站上 Google 演示的复制粘贴。

from __future__ import print_function
from googleapiclient.discovery import build
from httplib2 import Http
from oauth2client import file, client, tools

# If modifying these scopes, delete the file token.json.
SCOPES = 'https://www.googleapis.com/auth/presentations.readonly'

# The ID of a sample presentation.
PRESENTATION_ID = '<some id>'

def main():
    """Shows basic usage of the Slides API.
    Prints the number of slides and elments in a sample presentation.
    """
    # 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.
    # delete the file to for authentication and authorization again
    store = file.Storage('token.json')
    creds = store.get()

    if not creds or creds.invalid:
        # credentials.json is issued by Google for the application
        flow = client.flow_from_clientsecrets('credentials.json', SCOPES)
        creds = tools.run_flow(flow, store)

    service = build('slides', 'v1', http=creds.authorize(Http()))

    # Call the Slides API
    presentation = service.presentations().get(presentationId=PRESENTATION_ID).execute()
    slides = presentation.get('slides')

    print('The presentation contains {} slides:'.format(len(slides)))
    for i, slide in enumerate(slides):
        print('- Slide #{} contains {} elements.'.format(
            i + 1, len(slide.get('pageElements'))))


if __name__ == '__main__':
    main()

我能够升级大部分(我认为),但找不到tools.run_flow使用google-auth的等价物。下面是我的升级版,除了机制之外,它拥有一切(我认为)tools.run_flow。如何tools.run_flow使用google-auth完成?

from google.oauth2 import service_account
from google.auth.transport.requests import AuthorizedSession
from googleapiclient.discovery import build

SCOPES = ['https://www.googleapis.com/auth/presentations.readonly']
PRESENTATION_ID = '<some id>'

credentials = service_account.Credentials.from_service_account_file(
    "the-json-file.json",
    scopes=SCOPES
)    

service = build('slides', 'v1', credentials=credentials)
presentation = service.presentations().get(presentationId=PRESENTATION_ID).execute()
slides = presentation.get('slides')

print('The presentation contains {} slides:'.format(len(slides)))
for i, slide in enumerate(slides):
    print('- Slide #{} contains {} elements.'.format(
        i + 1, len(slide.get('pageElements'))))

当我使用google-auth方法运行上述代码时,我得到以下结果:

googleapiclient.errors.HttpError: <HttpError 403 when requesting https://slides.googleapis.com/v1/presentations/<some id>?alt=json returned "The caller does not have permission">

附加上下文,我正在尝试构建一个 Python 脚本来访问 Google 幻灯片以对幻灯片内容执行一些处理。我只是在阅读,而不是在写 Google 幻灯片。上面的代码是我尝试为我的 GSuite 帐户(我是我的组织的 GSuite 的管理员)处理访问 Google 幻灯片内容的身份验证和授权部分。使用旧oauth2client的第一个示例效果很好,但是由于不推荐使用oauth2client并且建议使用google-auth,因此我想使用最新的库以“正确”的方式进行操作。

更新

我用以下代码解决了部分问题:

from google.oauth2 import service_account
from google.auth.transport.requests import AuthorizedSession
from googleapiclient.discovery import build

from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow

import os
import json


def get_credentials():

    CLIENT_SECRET_FILE = '<some file>'
    SCOPES = ['https://www.googleapis.com/auth/presentations.readonly']

    credentials_path = '<some path>/token.json'

    if os.path.exists(credentials_path):
        # expect these to be valid. may expire at some point, but should be refreshed by google api client...
        return Credentials.from_authorized_user_file(credentials_path, scopes=SCOPES)
    else:
        flow = InstalledAppFlow.from_client_secrets_file(
            CLIENT_SECRET_FILE,
            scopes=SCOPES,
            redirect_uri='urn:ietf:wg:oauth:2.0:oob')

        auth_url, _ = flow.authorization_url(prompt='consent')

        print('Please go to this URL and finish the authentication flow: {}'.format(auth_url))
        code = input('Enter the authorization code: ')

        flow.fetch_token(code=code)
        credentials = flow.credentials

        credentials_as_dict = {
            'token': credentials.token,
            'refresh_token': credentials.refresh_token,
            'id_token': credentials.id_token,
            'token_uri': credentials.token_uri,
            'client_id': credentials.client_id,
            'client_secret': credentials.client_secret
        }

        with open(credentials_path, 'w') as file:
            file.write(json.dumps(credentials_as_dict))

        return credentials

# The ID of a sample presentation.
PRESENTATION_ID = '<some id>'

service = build('slides', 'v1', credentials=get_credentials())
presentation = service.presentations().get(presentationId=PRESENTATION_ID).execute()
slides = presentation.get('slides')

print('The presentation contains {} slides:'.format(len(slides)))
for i, slide in enumerate(slides):
    print('- Slide #{} contains {} elements.'.format(
        i + 1, len(slide.get('pageElements'))))

我现在的挑战是让网络浏览器自动打开。我可以复制并粘贴链接并手动获取代码,一切正常。理想情况下,我希望像在旧库中那样自动打开 Web 浏览器并捕获令牌。

解决了

将前面代码示例中的部分代码更新为:

    flow = InstalledAppFlow.from_client_secrets_file(
        CLIENT_SECRET_FILE,
        scopes=SCOPES,
        redirect_uri='urn:ietf:wg:oauth:2.0:oob')

    credentials = flow.run_local_server()

    credentials_as_dict = {
        'token': credentials.token,
        'refresh_token': credentials.refresh_token,
        'id_token': credentials.id_token,
        'token_uri': credentials.token_uri,
        'client_id': credentials.client_id,
        'client_secret': credentials.client_secret
    }

Web 浏览器会自动打开并捕获令牌值。一切都很好。

标签: pythonoauth2clientgoogle-auth-library

解决方案


推荐阅读