Как обновить токен доступа Google с помощью Django allauth?
Токен доступа для google обычно действует 1 час. Как обновить маркер без повторного входа пользователя в систему?
github код проекта: https://github.com/theptrk/learn_gcal
django-allauth Вход в Google настроен обычным способом с добавлением области видимости
THIRD_PARTY_APPS = [
# ...
"allauth.socialaccount",
"allauth.socialaccount.providers.google",
# This allows you to assign a site to a "social application"
SITE_ID = 1
SOCIALACCOUNT_PROVIDERS = {
"google": {
"SCOPE": [
# minimum scopes
"profile",
"email",
# additional scopes
"https://www.googleapis.com/auth/calendar.readonly",
],
"AUTH_PARAMS": {
"access_type": "offline",
},
}
}
# https://django-allauth.readthedocs.io/en/latest/configuration.html
# Use this for additional scopes: This defaults to false
SOCIALACCOUNT_STORE_TOKENS = True
Создание учетных данных отличается от документации, поскольку в документации используется "файл секретов" вместо получения токенов из базы данных
# get user and client credentials
token = SocialToken.objects.get(
account__user=request.user, account__provider="google"
)
client_id = env("GOOGLE_CLIENT_ID", default="")
client_secret = env("GOOGLE_CLIENT_SECRET", default="")
# create Credentials object
from google.oauth2.credentials import Credentials
creds=Credentials(
token=token.token,
refresh_token=token.token_secret,
token_uri="https://oauth2.googleapis.com/token",
client_id=client_id,
client_secret=client_secret,
)
Попытка получить события абсолютно нормальна, если токен доступа не просрочен
# retrieve google calendar events
from googleapiclient.discovery import build
from datetime import datetime
service = build("calendar", "v3", credentials=creds)
try:
events_result = (
service.events()
.list(
calendarId="primary",
timeMin=datetime.now().date().isoformat() + "Z",
maxResults=30,
singleEvents=True,
orderBy="startTime",
)
.execute()
)
except Exception as e:
print("Google API Error")
if e.status_code == 403:
if e.reason == "Request had insufficient authentication scopes.":
print("user needs to grant calendar scopes")
print("Token is likely expired at this point")
# I've tried:
# creds.refresh(...) but it hasnt worked
Из документации кажется, что если указать тип доступа как offline, то токен обновления будет получен при первом входе в систему и при повторных запросах аутентификации. Таким образом, насколько я понимаю, библиотека будет обрабатывать обновление токена аутентификации в фоновом режиме, когда это необходимо.
Если срок действия токена истечет, вы получите from google.auth.exceptions import RefreshError
ошибку и должны реализовать поток для повторной авторизации пользователя в вашем приложении.
# retrieve google calendar events
from googleapiclient.discovery import build
from datetime import datetime
from google.auth.exceptions import RefreshError
from googleapiclient.errors import HttpError
service = build("calendar", "v3", credentials=creds)
try:
events_result = (
service.events()
.list(
calendarId="primary",
timeMin=datetime.now().date().isoformat() + "Z",
maxResults=30,
singleEvents=True,
orderBy="startTime",
)
.execute()
)
except HttpError as e:
print("Google API Error")
if e.status_code == 403:
if e.reason == "Request had insufficient authentication scopes.":
print("user needs to grant calendar scopes")
except RefreshError as e:
# refresh token expired, start the flow for the user authorization
Причин истечения срока действия/отмены маркера обновления автономного доступа может быть несколько. Более подробная информация об этом здесь.
Надеюсь, это немного поможет!