1

我有一个 python 谷歌云函数,它接收 OAuth 授权代码作为参数。我想将此代码交换为可用于验证服务对象的令牌。

代码在外部生成并作为字符串参数传递给此函数。

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

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

4

2 回答 2

0

除了授权代码之外,您还需要更多信息。谷歌关于如何将授权码交换为访问令牌的文档在这里:刷新和访问令牌的交换授权码

具体来说,除了code,您还需要:

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

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

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

作为将所有这些配置存储在云函数中的替代方法,您可以使用托管 OAuth 服务,如Xkit我工作的地方),它处理授权过程并允许您从任何地方(包括云函数)检索访问令牌,只需一个 API钥匙。

于 2020-10-20T16:51:08.800 回答
0

我最近自己遇到了这个问题,试图访问 AdSense API。Google 的文档非常稀少,出于某种奇怪的原因使用 Flask,暗示您必须检索 anauthorization_response而不是实际的 authenticationcode并引用了一些不同的非工作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)将其转换为令牌,然后我将其存储在文件中以备将来重复使用adsense.dat

我遇到的问题是来自多个包的多个类用于存储 OAuth 凭据,并且它们都被混淆地命名为相同的东西,但它们有点不兼容。该flow.fetch_token()函数在内部将其凭据存储为一个google.oauth2.credentials.Credentials实例,但用于存储和加载这些凭据的代码只接受一个oauth2client.client.Credentials实例,因此我必须编写一些代码来从一个实例转换为另一个实例。

然后,要调用 API,您将拥有如下代码:

from utils import initialize_service

service = initialize_service()

result = service.reports().generate(
    startDate='<start date>',
    endDate='<end date>',
    filter=['AD_CLIENT_ID==<your ad client id>'],
    metric=[
        'PAGE_VIEWS',
        'EARNINGS'
    ],
    dimension=[
        'AD_UNIT_NAME',
    ],
).execute()
于 2021-04-22T14:13:01.670 回答