Как обновить токен доступа 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

Причин истечения срока действия/отмены маркера обновления автономного доступа может быть несколько. Более подробная информация об этом здесь.

Надеюсь, это немного поможет!

Вернуться на верх