Попытка доступа к веб-приложению Gsheet из Python 3.7 с использованием учетной записи службы - PullRequest
2 голосов
/ 10 февраля 2020

Code is not erroring according to logs Предыдущий связанный вопрос

Конфиг

  • Python 3.7
  • google-auth 1.11.0
  • google-auth-oauthlib 0.4.1
  • Учетные данные учетной записи службы Google
  • GSheet, предоставленный ServiceAccount
  • GSheet, представленный как Webapp
  • В Gsheet есть метод doGet, который читает лист, конвертирует его в CSV и возвращает его
  • Работает нормально, когда вы нажимаете его непосредственно в браузере
  • Не работает при использовании python

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

    b'<!DOCTYPE html><html><head><link rel="shortcut icon" 
    href="//ssl.gstatic.com/docs/script/images/favicon.ico"><title>Error</title><style 
    type="text/css">body {background-color: #fff; margin: 0; padding: 0;}.errorMessage {font- 
   family: Arial,sans-serif; font-size: 12pt; font-weight: bold; line-height: 150%; padding-top: 
    25px;}</style></head><body style="margin:20px"><div><img alt="Google Apps Script" 
    src="//ssl.gstatic.com/docs/script/images/logo.png"></div><div style="text- 
   align:center;font-family:monospace;margin:50px auto 0;max-width:600px">We&#39;re sorry, a 
    server error occurred. Please wait a bit and try again.</div></body></html>'

Нет ошибок в журналах.

Python код, выполняющий работу: -

from __future__ import print_function
from google.oauth2 import service_account
from google.auth.transport.urllib3 import AuthorizedHttp

SCOPES = ['https://www.googleapis.com/auth/spreadsheets',
      'https://www.googleapis.com/auth/drive',
      'https://www.googleapis.com/auth/drive.readonly']
credentials = service_account.Credentials.from_service_account_file(
'service_account.json', scopes=SCOPES)


def main():
try:
    authed_http = AuthorizedHttp(credentials)

    response = authed_http.request(
        'GET', "https://script.google.com/macros/s/AKfycbzmr5-g2ZIlsGFL5SDYdCYEKmhyqH_- 
QcAhFeBnfN0_D291kRA/exec")

    print(response._body)
except BaseException as err_base2:
    print(err_base2)

if __name__ == '__main__':
   main()

Is этот подход поддерживается. Чувствую, что я упускаю что-то очевидное.

Разрешения роли учетной записи службы для проекта GSheet Service Account Role Permissions to GSheet Project

Разрешения учетной записи службы для GSheet enter image description here

Поместите некоторые входы в запросы, но это больше не говорит нам. DEBUG: google.auth.transport.urllib3: выполнение запроса: POST https://oauth2.googleapis.com/token DEBUG: urllib3.connectionpool: запуск нового HTTPS-соединения (1): oauth2.googleapis.com:443 DEBUG: urllib3.connectionpool: https://oauth2.googleapis.com: 443"POST / token HTTP / 1.1" 200 Нет ОТЛАДКА: urllib3.connectionpool: Запуск нового HTTPS-соединения (1): script.google.com:443 ОТЛАДКА: urllib3.connectionpool: https://script.google.com: 443"GET / macros / s / AKfycbzmr5-g2ZIlsGFL5SDYdCYEKmhyqH_-QcAhFeBnfN0_D291kRA / exe c HTTP / 1.1" 500 Нет

1 Ответ

0 голосов
/ 12 февраля 2020

У меня была та же ошибка, что и у вас:

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

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

Если у вас есть домен G Suite - например, если вы используете G Suite - администратор домена G Suite может авторизовать приложение для доступа к пользовательским данным от имени пользователей в домене G Suite.

Итак, зачем вам выдавать себя за пользователя (реального человека)? это связано с тем, что служебная учетная запись - это бот (а не реальный человек), который используется для взаимодействия между серверами, что делает возможным, чтобы ваше приложение вызывало API Google, и хотя учетная запись службы имеет параметр client_email, который имеет структура, подобная name@project-randomnumber.iam.gserviceaccount.com, это не реальная электронная почта, которая принадлежит реальному человеку (я знаю, что это немного сбивает с толку).

Если вы отметите Развертывание скрипта как веб-приложения в 4-м Состояния шага:

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

Поэтому вы не можете использовать URL-адрес, предоставленный «Развернуть как веб-приложение». Чтобы реализовать делегирование на уровне домена в вашем коде, вы можете сделать это следующим образом:

from __future__ import print_function
from google.oauth2 import service_account
from google.auth.transport.urllib3 import AuthorizedHttp

SCOPES = ['https://www.googleapis.com/auth/spreadsheets', 'https://www.googleapis.com/auth/drive']
SERVICE_ACCOUNT_FILE = 'service_account.json'
# The user we want to "impersonate"
USER_EMAIL = "name@domain"

def main():
    try:
        credentials = service_account.Credentials.from_service_account_file(SERVICE_ACCOUNT_FILE, scopes=SCOPES)
        delegated_credentials = credentials.with_subject(USER_EMAIL)
        authed_http = AuthorizedHttp(delegated_credentials)
        response = authed_http.request('GET', "https://script.google.com/macros/s/<your-id>/exec")
        print(response._body)
    except BaseException as err_base2:
        print(err_base2)

if __name__ == '__main__':
   main()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...