Python Google API:使用 oauth2client.client 从刷新令牌中获取凭据
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/27771324/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Google API: getting Credentials from refresh token with oauth2client.client
提问by bjelli
I am using googles official oauth2client.client to access the google plus api. I have a refresh token (that does not expire) stored in a database, and need to recreate the temporary "Credentials" (access token) from that.
我正在使用 googles 官方 oauth2client.client 来访问 google plus api。我有一个存储在数据库中的刷新令牌(不会过期),并且需要从中重新创建临时“凭据”(访问令牌)。
But I could not find a way to do this with to official library supplied by google.
但是我找不到一种方法来使用谷歌提供的官方库来做到这一点。
So I hacked around it: used urllib to access the API that gives me a new access_token from the refresh_token. Using the access_token I can then use the library.
所以我绕过了它:使用 urllib 访问 API,该 API 为我提供了来自 refresh_token 的新 access_token。使用 access_token 然后我可以使用该库。
I must be missing somthing!
我一定是错过了什么!
from apiclient import discovery
from oauth2client.client import AccessTokenCredentials
from urllib import urlencode
from urllib2 import Request , urlopen, HTTPError
import json
# ==========================================
def access_token_from_refresh_token(client_id, client_secret, refresh_token):
request = Request('https://accounts.google.com/o/oauth2/token',
data=urlencode({
'grant_type': 'refresh_token',
'client_id': client_id,
'client_secret': client_secret,
'refresh_token': refresh_token
}),
headers={
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': 'application/json'
}
)
response = json.load(urlopen(request))
return response['access_token']
# ==========================================
access_token = access_token_from_refresh_token(CLIENT_ID, CLIENT_SECRET, REFRESH_TOKEN)
# now I can use the library properly
credentials = AccessTokenCredentials(access_token, "MyAgent/1.0", None)
http = credentials.authorize(httplib2.Http())
service = discovery.build('plus', 'v1', http=http)
google_request = service.people().get(userId='me')
result = google_request.execute(http=http)
回答by tjsar
You could store the entire credentials rather than only the refresh token:
您可以存储整个凭据,而不仅仅是刷新令牌:
json = credentials.to_json()
credentials = Credentials.new_from_json(json)
Look at the Storage objectwhich does it this way.
查看以这种方式执行此操作的Storage 对象。
回答by swdev
I solved this quite easily (you certainly miss this documentation). This is a snippet of my code that tries to use Picasa API to get all of album from active user:
我很容易地解决了这个问题(你肯定会错过这个文档)。这是我尝试使用 Picasa API 从活动用户获取所有相册的代码片段:
http = httplib2.Http(ca_certs=os.environ['REQUESTS_CA_BUNDLE'])
try:
http = self.oauth.credentials.authorize(http)
response, album_list = http.request(Picasa.PHOTOS_URL, 'GET')
if response['status'] == '403':
self.oauth.credentials.refresh(http)
response, album_list = http.request(Picasa.PHOTOS_URL, 'GET')
album_list = json.load(StringIO(album_list))
except Exception as ex:
Logger.debug('Picasa: error %s' % ex)
return {}
Use the refresh
method coming from oauth2client.client.OAuth2Credentials. I think it's even okay to use if response['status'] != '200'
. Got to check that!
使用refresh
来自oauth2client.client.OAuth2Credentials的方法。我认为甚至可以使用if response['status'] != '200'
. 必须检查一下!
回答by leah
I use: oauth2client.client.GoogleCredentials
我使用:oauth2client.client.GoogleCredentials
cred = oauth2client.client.GoogleCredentials(access_token,client_id,client_secret,
refresh_token,expires_at,"https://accounts.google.com/o/oauth2/token",some_user_agent)
http = cred.authorize(httplib2.Http())
cred.refresh(http)
self.gmail_service = discovery.build('gmail', 'v1', credentials=cred)
回答by Eugene Yarmash
You can construct an OAuth2Credentials
instance directly like this:
你可以OAuth2Credentials
像这样直接构造一个实例:
import httplib2
from oauth2client import GOOGLE_REVOKE_URI, GOOGLE_TOKEN_URI, client
CLIENT_ID = '<client_id>'
CLIENT_SECRET = '<client_secret>'
REFRESH_TOKEN = '<refresh_token>'
credentials = client.OAuth2Credentials(
access_token=None, # set access_token to None since we use a refresh token
client_id=CLIENT_ID,
client_secret=CLIENT_SECRET,
refresh_token=REFRESH_TOKEN,
token_expiry=None,
token_uri=GOOGLE_TOKEN_URI,
user_agent=None,
revoke_uri=GOOGLE_REVOKE_URI)
credentials.refresh(httplib2.Http()) # refresh the access token (optional)
print(credentials.to_json())
http = credentials.authorize(httplib2.Http()) # apply the credentials
回答by 599644
Wow.. 2 years old question and not a good answer.. No surprise given that Google documentation is crap regarding this.
哇.. 2 岁的问题,而不是一个好的答案.. 考虑到谷歌文档在这方面是废话也就不足为奇了。
The correct way to do this is by extending the Storage class oauth2client.client.Storage
正确的方法是扩展 Storage 类 oauth2client.client.Storage
An example implementation(using mongodbcollection _google_credentials
) would be something like:
一个示例实现(使用mongodbcollection _google_credentials
)类似于:
class Storage(oauth2client.client.Storage):
def __init__(self, key):
super(Storage, self).__init__()
self._key = key
def locked_get(self):
if not self._key: return None
data = _google_credentials.find_one({'_id': self._key})
if not data: return None
credentials = oauth2client.client.Credentials.new_from_json(json.dumps(data))
credentials.set_store(self)
return credentials
def locked_put(self, credentials):
data = json.loads(credentials.to_json())
_google_credentials.update_one({'_id': self._key}, {'$set': data},
upsert=True)
credentials.set_store(self)
def locked_delete(self):
bucket.delete(self._key)
Then when you initially get the credentials after step2_exchange
, you need to store them using Storage().put
:
然后,当您最初获得凭证后step2_exchange
,您需要使用Storage().put
以下方式存储它们:
e.g:
例如:
credentials = flow.step2_exchange(code)
Storage(user_id).put(credentials)
When you need the credentials again, just do:
当您再次需要凭据时,只需执行以下操作:
credentials = Storage(user_id).get()
回答by KiHyun Nam
I recommend this method.
我推荐这种方法。
from oauth2client import client, GOOGLE_TOKEN_URI
CLIENT_ID = "client_id"
CLIENT_SECRET = "client_secret"
REFRESH_TOKEN = "refresh_token"
credentials = client.OAuth2Credentials(
access_token = None,
client_id = CLIENT_ID,
client_secret = CLIENT_SECRET,
refresh_token = REFRESH_TOKEN,
token_expiry = None,
token_uri = GOOGLE_TOKEN_URI,
token_ id = None,
revoke_uri= None)
http = credentials.authorize(httplib2.Http())
Even if the access token has expired, the credential is still authorize because of the refresh token.
即使访问令牌已过期,由于刷新令牌,凭证仍然是授权的。
回答by Ray Hulha
If you are using the 2018 Youtube Python Quickstart demo appusing google-auth, you can't use oauth2client's storage.
如果您使用 google-auth使用2018 Youtube Python Quickstart 演示应用程序,则不能使用 oauth2client 的存储。
So here is the correct way of storing the credentials
Here is a partially working solution for google-auth, missing the correct handling of the case where the token expires:
这是 google-auth 的部分工作解决方案,缺少对令牌过期情况的正确处理:
import os
import json
import os.path
import google.oauth2.credentials
from google.oauth2.credentials import Credentials
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
from google_auth_oauthlib.flow import InstalledAppFlow
CLIENT_SECRETS_FILE = "client_secret.json"
SCOPES = ['https://www.googleapis.com/auth/youtube.force-ssl']
API_SERVICE_NAME = 'youtube'
API_VERSION = 'v3'
def get_authenticated_service():
if os.path.isfile("credentials.json"):
with open("credentials.json", 'r') as f:
creds_data = json.load(f)
creds = Credentials(creds_data['token'])
else:
flow = InstalledAppFlow.from_client_secrets_file(CLIENT_SECRETS_FILE, SCOPES)
creds = flow.run_console()
creds_data = {
'token': creds.token,
'refresh_token': creds.refresh_token,
'token_uri': creds.token_uri,
'client_id': creds.client_id,
'client_secret': creds.client_secret,
'scopes': creds.scopes
}
print(creds_data)
with open("credentials.json", 'w') as outfile:
json.dump(creds_data, outfile)
return build(API_SERVICE_NAME, API_VERSION, credentials = creds)
def channels_list_by_username(service, **kwargs):
results = service.channels().list(**kwargs).execute()
print('This channel\'s ID is %s. Its title is %s, and it has %s views.' %
(results['items'][0]['id'],
results['items'][0]['snippet']['title'],
results['items'][0]['statistics']['viewCount']))
if __name__ == '__main__':
os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'
service = get_authenticated_service()
channels_list_by_username(service, part='snippet,contentDetails,statistics', forUsername='GoogleDevelopers')
回答by Neil
In case anyone is looking for the answer for how use a refresh token with google_auth_oauthlib
, the following works for me:
如果有人正在寻找如何使用刷新令牌的答案google_auth_oauthlib
,以下对我有用:
flow.oauth2session.refresh_token(flow.client_config['token_uri'],
refresh_token=refresh_token,
client_id=<MY_CLIENT_ID>,
client_secret=flow.client_config['client_secret'])
creds = google_auth_oauthlib.helpers.credentials_from_session(
flow.oauth2session, flow.client_config)
I cannot find anywhere where this is documented though.
不过,我找不到任何记录此内容的地方。