Проблема хронического тайм-аута с 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, этот подход должен работать по крайней мере для целей тестирования.