Обнаружение отмены токена oAuth Google API - PullRequest
1 голос
/ 03 октября 2019

Я использую скрипт быстрого запуска Google Python отсюда: https://developers.google.com/calendar/quickstart/python

Он отлично работает в нормальных условиях. Я могу разрешить ему доступ к моей учетной записи Gmail, и он может создавать записи Календаря Google.

Если я войду в свою учетную запись Gmail через браузер, перейдите в раздел Безопасность и отзовите доступ моего приложения к моей учетной записи Google,скрипт быстрого старта не подхватывает его. Он просто падает:

$ python quickstart.py
Getting the upcoming 10 events
Traceback (most recent call last):
  File "quickstart.py", line 52, in <module>
    main()
  File "quickstart.py", line 42, in main
    orderBy='startTime').execute()
  File "/opt/my_project/venv3/lib/python3.6/site-packages/googleapiclient/_helpers.py", line 130, in positional_wrapper
    return wrapped(*args, **kwargs)
  File "/opt/my_project/venv3/lib/python3.6/site-packages/googleapiclient/http.py", line 851, in execute
    method=str(self.method), body=self.body, headers=self.headers)
  File "/opt/my_project/venv3/lib/python3.6/site-packages/googleapiclient/http.py", line 165, in _retry_request
    resp, content = http.request(uri, method, *args, **kwargs)
  File "/opt/my_project/venv3/lib/python3.6/site-packages/google_auth_httplib2.py", line 213, in request
    self.credentials.refresh(self._request)
  File "/opt/my_project/venv3/lib/python3.6/site-packages/google/oauth2/credentials.py", line 136, in refresh
    self._client_secret))
  File "/opt/my_project/venv3/lib/python3.6/site-packages/google/oauth2/_client.py", line 237, in refresh_grant
    response_data = _token_endpoint_request(request, token_uri, body)
  File "/opt/my_project/venv3/lib/python3.6/site-packages/google/oauth2/_client.py", line 111, in _token_endpoint_request
    _handle_error_response(response_body)
  File "/opt/my_project/venv3/lib/python3.6/site-packages/google/oauth2/_client.py", line 61, in _handle_error_response
    error_details, response_body)
google.auth.exceptions.RefreshError: ('invalid_grant: Token has been expired or revoked.', '{\n  "error": "invalid_grant",\n  "error_description": "Token has been expired or revoked."\n}')

Если я добавлю несколько строк отладки непосредственно перед строкой, которая выдает исключение, я вижу это:

creds.valid: True
creds.expired: False

Я знаю, что могу просто поймать google.auth.exceptions.RefreshError. Проблема, с которой я столкнулся, состоит в том, что в начале файла quickstart.py имеется целый раздел кода, целью которого является определение допустимости токена, но, по-видимому, он не может обнаружить этот довольно простой сценарий, и исключение не выдается доЯ на самом деле пытаюсь использовать токен для выполнения команды. Помещение каждого отдельного выполнения (или, по крайней мере, первого) в блок try-exc на случай, если первая часть скрипта не может выполнить свою задачу по обнаружению того, что токен отозван, кажется глупым.

Есть лиспособ обнаружить, что сертификат был отозван, прежде чем я на самом деле пытаюсь его использовать? Почему не работают creds.valid и creds.expired?

Обновление. Похоже, что если вы подождете достаточно долго (несколько минут или часов - не уверены), в конечном итоге отобразятся creds.valid и creds.expired. что учетные данные больше не действительны. Однако в этот промежуток времени, когда учетные данные кажутся действительными, но не могут быть использованы, достаточно, чтобы моя программа аварийно завершилась, если я не обработал ее правильно.

Обновление 2: единственное, что яМожно подумать просто запустить что-то вроде:

from googleapiclient.discovery import build
from google.auth.exceptions import RefreshError

...
try:
    service = build('calendar', 'v3', credentials=creds)
    service.events().list(calendarId='primary', maxResults=1).execute()
except RefreshError:
    ...
...

сразу после кода, который проверяет, действительны ли учетные данные. Вроде как окончательная проверка. Это работает, но выглядит немного грязно, поскольку требует дополнительного вызова к серверам API Google, и в основном это именно то, что я сказал выше - поместить первое выполнение в блок try-Кроме. Нет лучшего способа?

1 Ответ

1 голос
/ 04 октября 2019

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

    # If there are no (valid) credentials available, let the user log in.
    if creds and creds.refresh_token:
        try:
            creds.refresh(Request())
        except RefreshError:
            logger.error("Credentials could not be refreshed, possibly the authorization was revoked by the user.")
            os.unlink('token.pickle')
            return
    else:
        flow = InstalledAppFlow.from_client_secrets_file(
            'credentials.json', SCOPES)
        creds = flow.run_local_server(port=0)
    # Save the credentials for the next run
    with open('token.pickle', 'wb') as token:
        pickle.dump(creds, token)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...