Каков правильный механизм аутентификации в Google в автономном скрипте Python?

У меня есть код, который я использую для извлечения адреса электронной почты из контактов Gmail в текстовый файл. Это простой скрипт Python, который запускается в задании cron и основан на библиотеке gdata Python (в настоящее время версии 2.0.18).

По сравнению с предыдущим месяцем, это больше не работает из-за того, что Google отказывается от протокола ClientLogin . Полученная ошибка выглядит так:

{'status': 401, 'body': '<?xml version="1.0" encoding="UTF-8"?>\n<errors xmlns="http://schemas.google.com/g/2005">\n <error>\n <domain>GData</domain>\n <code>required</code>\n <location type="header">Authorization</location>\n <internalReason>Login Required</internalReason>\n </error>\n</errors>\n', 'reason': 'Unauthorized'} 

Я знал, что это происходит и обрабатывается в других местах (например, приложения AppEngine), но забыл, что мне придется преобразовать этот скрипт. Теперь, когда я здесь, я обнаружил, что понятия не имею, как я должен выполнять эту работу.

Все ссылки, которые я нашел, например, здесь, в блоге разработчиков Google Apps или здесь и здесь, в StackOverflow, предполагают, что решение должно использовать OAuth2Token. Однако для этого требуется идентификатор клиента и клиентский секрет с консоли Google API, которая привязана к приложению. У меня нет приложения. Я просто хочу аутентифицироваться из своего сценария.

Может кто-нибудь, пожалуйста, предложите правильный способ сделать это в автономном скрипте? Или мне не повезло, и нет никакого механизма для этого?

Это мужество существующего кода контактов:

 from gdata.contacts.service import ContactsService, ContactsQuery user = "myuser@gmail.com" password = "mypassword" addresses = set() client = ContactsService(additional_headers={"GData-Version":"2"}) client.ssl = True client.ClientLogin(user, password) groups = client.GetGroupsFeed() for group in groups.entry: if group.content.text == "System Group: My Contacts": query = ContactsQuery() query.max_results = 9999 # large enough that we'll get "everything" query.group = group.id.text contacts = client.GetContactsFeed(query.ToUri()) for contact in contacts.entry: for email in contact.email: addresses.add(email.address.lower()) break return addresses 

В идеале я хочу заменить client.ClientLogin() другим механизмом, который сохраняет остальную часть кода с помощью gdata. Альтернативно, если это невозможно сделать с gdata, я открыт для преобразования в другую библиотеку, которая предлагает аналогичную функциональность.

2 Solutions collect form web for “Каков правильный механизм аутентификации в Google в автономном скрипте Python?”

Может кто-нибудь, пожалуйста, предложите правильный способ сделать это в автономном скрипте? Или мне не повезло, и нет никакого механизма для этого?

Механизм больше не похож на тот, который вы используете. Вам нужно будет создать проект Cloud Developer и использовать OAuth2 и переписать сценарий.

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

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

В итоге оказалось проще просто взломать скрипт оболочки, используя завиток, чем беспорядок с библиотекой gdata. Как и ожидалось, я смог выполнить большую часть процесса проверки вручную, вне сценария, в соответствии с инструкциями потока устройства OAuth2 .

После завершения процесса проверки у меня было 4 требуемых мандата: идентификатор клиента, секрет клиента, токен доступа и токен обновления. По документации Google, токен доступа в конце концов истекает. Вы можете получить новый токен доступа, попросив диспетчера токенов обновить токен. Когда вы это делаете, вы, видимо, получаете новый токен доступа, но не новый токен обновления.

Я храню идентификатор клиента и секрет и токен обновления в файле CREDENTIALS в формате JSON. Поскольку токен доступа изменяется со временем, он сохраняется в файле ACCESS , также в формате JSON.

Важные части сценария показаны ниже:

 #!/bin/ksh CLIENT_ID=$(cat ${CREDENTIALS} | jq -r ".client_id") CLIENT_SECRET=$(cat ${CREDENTIALS} | jq -r ".client_secret") REFRESH_TOKEN=$(cat ${CREDENTIALS} | jq -r ".refresh_token") ACCESS_TOKEN=$(cat ${ACCESS} | jq -r ".access_token") CONTACTS_URL="https://www.google.com/m8/feeds/contacts/default/full?access_token=${ACCESS_TOKEN}&max-results=5000&v=3.0" ERROR=$(curl --show-error --silent --fail "${CONTACTS_URL}" -o ${CONTACTS_XML} 2>&1) RESULT=$? if [[ ${RESULT} -eq 0 ]] then cat ${CONTACTS_XML} | grep 'gd:email' | sed 's/^.*address="//g' | sed 's/".*$//g' | tr '[:upper:]' '[:lower:]' | sort | uniq elif [[ ${RESULT} -eq 22 ]] then echo "${ERROR}" | grep -q "401" if [[ $? -eq 0 ]] then TOKEN_URL="https://www.googleapis.com/oauth2/v3/token" REFRESH_PARAMS="client_id=${CLIENT_ID}&client_secret=${CLIENT_SECRET}&refresh_token=${REFRESH_TOKEN}&grant_type=refresh_token" ERROR=$(curl --show-error --silent --fail --data "${REFRESH_PARAMS}" ${TOKEN_URL} -o ${REFRESH_JSON}) RESULT=$? if [[ ${RESULT} -eq 0 ]] then ACCESS_TOKEN=$(cat ${REFRESH_JSON} | jq -r ".access_token") jq -n --arg access_token "${ACCESS_TOKEN}" '{"access_token": $access_token, }' > ${ACCESS} CONTACTS_URL="https://www.google.com/m8/feeds/contacts/default/full?access_token=${ACCESS_TOKEN}&max-results=5000&v=3.0" ERROR=$(curl --show-error --silent --fail "${CONTACTS_URL}" -o ${CONTACTS_XML} 2>&1) RESULT=$? if [[ ${RESULT} -eq 0 ]] then cat ${CONTACTS_XML} | grep 'gd:email' | sed 's/^.*address="//g' | sed 's/".*$//g' | tr '[:upper:]' '[:lower:]' | sort | uniq else print "Unexpected error: ${ERROR}" >&2 exit 1 fi else print "Unexpected error: ${ERROR}" >&2 exit 1 fi else print "Unexpected error: ${ERROR}" >&2 exit 1 fi else print "Unexpected error: ${ERROR}" >&2 exit 1 fi 

Это не самая красивая вещь в мире, но я искал что-то быстро-грязное, и это работает.

  • Токен доступа и токен обновления, предоставляющий недействительный грант в Google Plus на Python?
  • Можно ли использовать «делегирование полномочий домена» с помощью gdata-python-client?
  • Не разрешено запрашивать области - Google OAuth2 для устройств
  • Python - как пройти проверку подлинности с помощью Google Analytics от AWS Lambda?
  • Python - лучший язык программирования в мире.