Oauth2 для доступа к API Google, по-видимому, зависит от идентификатора пользователя запрашивающей задачи Python

#python #google-api #google-oauth #gmail-api #google-api-php-client

Вопрос:

Я переписываю программу, которой нужна возможность отправлять и получать электронные письма. Старая версия работает автономно на рабочем столе и использует SMTP и POP3 для отправки и получения от моего имени с помощью учетной записи gmail. Это нормально, но в последнее время многие отправленные электронные письма оказались в папках нежелательной почты. Итак, я хотел бы получить более надежный способ «отправки от имени» пользователя (меня). Новая версия представляет собой веб-приложение, а не настольную программу, поэтому действия по электронной почте выполняются на стороне сервера, и я пытаюсь использовать Gmail API.

Я застрял на несколько дней из-за невозможности получить маркер доступа к API («недопустимый маркер») при запуске процесса на сервере. Вот что я сделал:

  1. Используйте консоль облачной платформы Google для создания/загрузки файла учетных данных.json
  2. Используйте код python «быстрый запуск» для успешного тестирования авторизации пользователя, сохраняя токены в виде маркера файла.json и отправить тестовое сообщение
  3. Включите аналогичный код в мою программу, но запустите его в качестве теста из командной строки > успешно!
  4. Скопируйте всю папку на мой сервер и с помощью SSH-терминала запустите ее снова в качестве теста из командной строки > Успешно (включая использование маркера обновления)!
  5. Запустите его как веб-приложение (WSGI Python), и он завершится неудачей.

Заметив, что владельцем задачи не являюсь я, когда она запускается как веб-приложение на терминале SSH, я сменил пользователя на «www-данные», повторил тест и выдал ошибку (cred.valid == False) после

creds = Credentials.from_authorized_user_file('token.json', scopes=SCOPES) В результате запускается поток аутентификации пользователя, который останавливается, поскольку его нельзя использовать удаленно (я полагаю).

Я позаботился о том, чтобы все файлы в папке были одинаково доступны обоим пользователям (www-data и ben). Может ли кто-нибудь подсказать мне, что мне нужно сделать, чтобы заставить его работать с пользователем «www-данные»?

 def get_credentials():

    # If modifying these scopes, delete the file token.json.
    SCOPES = ['https://www.googleapis.com/auth/gmail.readonly','https://www.googleapis.com/auth/gmail.send']

    creds = None
    # The file token.json stores the user's access and refresh tokens, and is
    # created automatically when the authorization flow completes for the first
    # time.
    logging("In get_credentials. Python version: "   sys.version )
    if os.path.exists('token.json'):
        logging("Using token.json")
        with open('token.json',"r",encoding="utf-8") as fi:
            s = fi.read()
            logging( s )
        logging( str(os.environ))
        creds = Credentials.from_authorized_user_file('token.json', scopes=SCOPES)
        logging("Creds "   str(creds))

        logging(str(creds.refresh_token)   " "   str( creds.expired)   " "   str( creds.valid))
        
    # If there are no (valid) credentials available, let the user log in.
    if not creds or not creds.valid:
        logging("No valid credentials found")
        if creds and creds.expired and creds.refresh_token:
            logging("Going for a refresh")
            creds.refresh(Request())
        else:
            logging("Going for live authentication flow!")
            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.json', 'w') as token:
            token.write(creds.to_json())
            logging("Saved token.json")

    service = build('gmail', 'v1', credentials=creds)


    return service
 

Ответ №1:

Проблема, с которой вы столкнулись, заключается в том, что вы используете InstalledAppFlow. Это приведет к появлению экрана согласия на компьютере, на котором выполняется код, а затем сохранит токен обновления и токен доступа в файле token.json.

Что вы могли бы сделать, так это запустить его один раз локально, чтобы убедиться, что этот токен.создается json, а затем убедитесь, что при загрузке его на сервер этот токен.также загружается json.

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

Комментарии:

1. Спасибо за быстрый ответ! Я запустил его локально, чтобы создать токен. json и включил этот файл при загрузке на сервер. Вот как все прошло нормально в качестве теста командной строки на сервере. Я не думаю, что смогу одобрить заявку как «производственную», поэтому ограничение на семь дней будет проблемой. Есть ли лучший подход?

2. Токены обновления для приложений, находящихся в процессе тестирования, не обновляются только в течение семи дней. Затем вам нужно будет снова авторизовать его.