我有一个python谷歌云函数,它接收OAuth授权代码作为参数。我想将此代码交换为一个令牌,该令牌可用于对服务对象进行身份验证。
代码是从外部生成的,并作为字符串参数传递给此函数。
我已经看了google_auth_oauthlib.flow的文档。但它希望创建一个流对象来处理身份验证。在我的情况下,我只有代码作为结果。
如何将授权码作为字符串交换为令牌?
您需要的信息不仅仅是授权代码。谷歌关于如何将授权码交换为访问令牌的文档如下:为刷新和访问令牌交换授权码。
具体来说,除了code
,您还需要:
client_id
:从API控制台获取的客户端ID[凭据页]|(https://console.developers.google.com/apis/credentials)client_secret
:从API控制台凭据页面获取的客户端机密grant_type
:authorization_code
redirect_uri
:初始授权请求中使用的重定向URI。如果这是针对可能是urn:ietf:wg:oauth:2.0:oob
(用于带外(的CLI(或类似程序(
其中大多数(client_id
、client_secret
、grant_type
(都是静态的,因此您可以将它们用作云功能中的配置。如果您确信生成code
的流,那么redirect_uri
可能是静态的。
有了这些信息,您应该能够在链接的示例中创建Flow对象并获取令牌。
作为将所有这些配置存储在云功能中的替代方案,您可以使用像Xkit(我工作的地方(这样的托管OAuth服务,该服务处理授权过程,并允许您仅使用API密钥从任何位置(包括云功能(检索访问令牌。
我最近在尝试访问AdSense API时遇到了这个问题。谷歌的文档非常稀疏,出于某种奇怪的原因使用Flask,暗示你必须检索authorization_response
而不是实际授权code
,并引用了一些不同的不工作的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%sn' % 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()