Google API: получение учетных данных из токена обновления с помощью oauth2client.client

Я использую googles официальный oauth2client.client для доступа к Google плюс api. У меня есть токен обновления (который не истекает), хранящийся в базе данных, и нужен чтобы воссоздать временные "Учетные данные" (токен доступа).

Но я не мог найти способ сделать это с официальной библиотекой, предоставленной Google.

Итак, я взломал его: использовал urllib для доступа к API, который дает мне новый access_token из refresh_token. Используя access_token, я могу использовать библиотеку.

Мне нужно пропустить что-то!

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)

Ответ 1

Я использую: 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)

Ответ 2

Я решил это довольно легко (вы, конечно, пропустите эту документацию). Это фрагмент моего кода, который пытается использовать 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 {}

Используйте метод refresh, исходящий из oauth2client.client.OAuth2Credentials. Я думаю, что даже использовать if response['status'] != '200'. Надо проверить это!

Ответ 3

Вы можете хранить все учетные данные, а не только токен обновления:

json = credentials.to_json()
credentials = Credentials.new_from_json(json)

Посмотрите на объект хранения, который делает это таким образом.

Ответ 4

Вы можете создать OAuth2Credentials экземпляр непосредственно следующим образом:

import httplib2
from oauth2client import client, GOOGLE_TOKEN_URI, GOOGLE_REVOKE_URI

CLIENT_ID = "<client identifier>"
CLIENT_SECRET = "<client secret>"
REFRESH_TOKEN = "<refresh_token>"

credentials = client.OAuth2Credentials(
    None, CLIENT_ID, CLIENT_SECRET, REFRESH_TOKEN, None, GOOGLE_TOKEN_URI,
    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

Ответ 5

Ничего себе.. 2-летний вопрос и не хороший ответ. Не удивительно, что документация Google - это дерьмо в этом отношении.

Правильный способ сделать это - расширить класс хранения oauth2client.client.Storage

Пример реализации (с использованием коллекции mongodb _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)

Затем, когда вы сначала получаете учетные данные после step2_exchange, вам необходимо сохранить их с помощью Storage().put:

например:

credentials = flow.step2_exchange(code)
Storage(user_id).put(credentials)

Когда вам снова потребуются учетные данные, просто выполните:

credentials = Storage(user_id).get()

Ответ 6

Я рекомендую этот метод.

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())

Даже если токен доступа истек, учетные данные все еще авторизуются из-за токена обновления.