Проблема хронического тайм-аута с API Google через Python?

Я работаю над небольшим веб-приложением, которое поможет мне управлять своей электронной почтой. Я настроил его через API Google с помощью следующей функции, используя токен OAuth, полученный через django-allauth,

import google.oauth2.credentials
from .choices import GMAIL
from allauth.socialaccount.models import SocialToken, SocialAccount
from apiclient.discovery import build


def get_credentials(user):
    account = SocialAccount.objects.get(user=user.id)
    token = SocialToken.objects.get(app=GMAIL, account=account).token
    credentials = google.oauth2.credentials.Credentials(token)
    service = build('gmail', 'v1', credentials=credentials)
    return service

Кажется, иногда это работает, но, к сожалению, это не очень надежно. Это часто бывает в build() функция, выполняющаяся только около трети времени. Мне интересно, что может вызвать такое поведение, и если есть более надежный способ доступа к API?

Я нашел следующее AuthorizedSession класс из этих документов:

from google.auth.transport.requests import AuthorizedSession

authed_session = AuthorizedSession(credentials)

response = authed_session.request(
    'GET', 'https://www.googleapis.com/storage/v1/b')

Но я не знаю, как превратить его в объект, который работает с API Google:

def get_labels(user):
    service = get_credentials(user)
    results = service.users().labels().list(userId='me').execute()
    labels = results.get('labels', [])
    return labels

К сожалению, документы Google рекомендуют использовать устаревший пакет, который я надеялся избежать.

Я впервые использую OAuth-принудительный API. У кого-нибудь есть совет?

РЕДАКТИРОВАТЬ: я опубликовал после попытки с моего MacBook. Я также попробовал это сделать на своей машине с Windows, где она работает более последовательно, но каждый раз это занимает около 20 секунд. build(), Я чувствую, что делаю что-то не так.

1 ответ

Решение

Это работает намного лучше этим утром после того, как я наконец добавил токен обновления в смесь. Возможно, его отсутствие вызывало некоторые проблемы на другом конце. Я продолжу тестирование, но сейчас все работает хорошо:

Вот мое полное решение:

import google.oauth2.credentials
from google.auth.transport.requests import Request

from apiclient import errors, discovery

from myproject.settings import GMAIL_CLIENT_API_KEY, GMAIL_CLIENT_API_SECRET


def get_credentials(user):
    token_set = user.socialaccount_set.first().socialtoken_set.first()
    token = token_set.token
    refresh_token = token_set.token_secret
    credentials = google.oauth2.credentials.Credentials(
        token,
        refresh_token=refresh_token,
        client_id=GMAIL_CLIENT_API_KEY,
        client_secret=GMAIL_CLIENT_API_SECRET,
        token_uri= google.oauth2.credentials._GOOGLE_OAUTH2_TOKEN_ENDPOINT,
    )

    if credentials.expired:
        request = Request()
        credentials.refresh(request)

    service = discovery.build('gmail', 'v1', credentials=credentials)
    return service

Как видите, я добавил свои ключи API в файл настроек и сослался на них здесь. Я случайно наткнулся на token_uri в то время как носился вокруг в исходных файлах вчера. refresh_token был кусок, который потребовалось больше всего, чтобы найти.

Хорошей новостью является то, что Django-Allauth сохранит токен обновления в SocialToken модель под token_secret колонка. Однако это будет сделано только в том случае, если в ваших настройках указано следующее:

SOCIALACCOUNT_PROVIDERS = {
    'google': {
        'SCOPE': [
            'profile',
            'email',
            'https://www.googleapis.com/auth/gmail.labels',
            'https://www.googleapis.com/auth/gmail.modify'
        ],
        'AUTH_PARAMS': {
            'access_type': 'offline',
        }
    }
}

В частности, access_type в AUTH_PARAMS должен быть установлен в 'offline' в соответствии с документами.

Теперь это по-прежнему будет создавать проблемы, если вы подключили свою учетную запись до того, как применили это изменение, поэтому вам также придется отозвать доступ к своему приложению через разрешения Google, чтобы получить новый токен обновления. Подробнее об этом можно узнать в этом вопросе.

Я не уверен, является ли это правильным / намеченным способом сделать это, но пока Google не обновит свои документы для Django, этот подход должен работать по крайней мере для целей тестирования.

Другие вопросы по тегам