Python-Google OAuth根据授权代码生成令牌

问题描述

我有一个python google cloud函数,该函数接收OAuth授权代码作为参数。我想将此代码交换为可用于认证服务对象的令牌。

代码是在外部生成的,并以字符串的形式传递给该函数

我看过google_auth_oauthlib.flow的文档。但它期望创建一个流对象来处理auth。就我而言,我只有代码作为结果。

如何将授权码作为字符串交换为令牌?

解决方法

您需要的信息不仅仅是授权码。有关如何将授权码转换为访问令牌的Google文档,请参见:Exchange authorization code for refresh and access tokens

尤其是,除了code之外,您还需要:

  • client_id:从API控制台[凭据页面] |(https://console.developers.google.com/apis/credentials)获得的客户端ID。
  • client_secret:从API控制台Credentials page获得的客户端密码。
  • grant_typeauthorization_code
  • redirect_uri:在初始授权请求中使用的重定向URI。如果是用于CLI(或类似)的CLI(可能是urn:ietf:wg:oauth:2.0:oob(用于带外)

其中大多数(client_idclient_secretgrant_type)是静态的,因此您可以将它们用作云功能中的配置。如果您确定生成redirect_uri的流程,那么code可以是静态的。

有了这些信息,您应该能够在链接的示例中创建Flow对象并获取令牌。

作为将所有此配置存储在云功能中的一种替代方法,您可以使用托管的OAuth服务,例如Xkit(在我工作的地方 ),该服务可以处理授权过程并让您仅使用API​​密钥即可从任何地方(包括云功能)检索访问令牌。

,

我最近在尝试访问 AdSense API 时遇到了这个问题。 Google 的文档非常稀疏,出于某种奇怪的原因使用 Flask,这意味着您必须检索 authorization_response 而不是实际授权 code,并引用 a few 不同的 { {3}} Python 示例,似乎是为早已弃用的 Python 1.4 编写的。

但是,根据他们的示例以及一些实现了一些最新修复的博客文章(但在我尝试时仍然损坏),我设法拼凑了一些工作代码。

我的文件 utils.py,我在其中定义了 initialize_service 以初始化我与 AdSense API 的连接:

"""
Auxiliary file for AdSense Management API code samples.
Handles various tasks to do with logging,authentication and initialization.
"""

import os

from apiclient.discovery import build

from oauth2client.client import OAuth2Credentials
from oauth2client.file import Storage
from googleapiclient.http import build_http

import google_auth_oauthlib.flow

MY_DOMAIN = '<your domain here>'

def initialize_service():
    """Builds instance of service from discovery data and does auth."""

    client_secrets = os.path.join(os.path.dirname(__file__),'client_secrets.json')

    flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
        client_secrets,scopes=['https://www.googleapis.com/auth/adsense.readonly'])
    flow.redirect_uri = f'https://{MY_DOMAIN}/oauth2callback'

    # If the credentials don't exist or are invalid run through the native client
    # flow. The Storage object will ensure that if successful the good
    # Credentials will get written back to a file.
    storage = Storage('adsense.dat')
    credentials = storage.get()
    if credentials is None or credentials.invalid:

        auth_url,_ = flow.authorization_url(prompt='consent')
        print('Log into the Google Account you use to access your AdWords account ' \
         'and go to the following URL: \n%s\n' % auth_url)
        print('After approving the token enter the verification code (if specified).')
        code = input('Code:').strip()

        flow.fetch_token(code=code)
        print('Access token: %s' % flow.credentials.token)
        print('Refresh token: %s' % flow.credentials.refresh_token)

        # Flow creates a google.oauth2.credentials.Credentials instance but storage
        # can only save and load a oauth2client.client.Credentials
        # instance,so we have to convert it.
        old_creds = flow.credentials
        good_creds = OAuth2Credentials(
            access_token=old_creds.token,client_id=old_creds.client_id,client_secret=old_creds.client_secret,refresh_token=old_creds.refresh_token,token_expiry=old_creds.expiry,token_uri=old_creds.token_uri,user_agent='my-agent',id_token=old_creds.id_token,scopes=old_creds.scopes,)
        storage.put(good_creds)
        credentials = storage.get()

    http = credentials.authorize(http=build_http())

    service = build("adsense","v1.4",http=http)

    return service

这是应该回答您的问题的代码,因为我获得了授权代码,然后调用 flow.fetch_token(code=code) 将其转换为令牌,然后我将其存储在文件 {{1} 中以备将来重用}.

我遇到的问题是来自多个包的多个类用于存储 OAuth 凭据,并且它们都以相同的名称令人困惑地命名,但它们有点不兼容。 adsense.dat 函数在内部将其凭据存储为一个 flow.fetch_token() 实例,但是用于存储和加载这些凭据的代码仅接受一个 google.oauth2.credentials.Credentials 实例,因此我不得不编写一些代码来从一个实例进行转换到另一个。

然后,要调用 API,您需要编写如下代码:

oauth2client.client.Credentials