尝试刷新令牌时出现 python 错误的 Google API

问题描述 投票:0回答:1

所以我尝试用 python 3.8.5 编写这个程序,它与 Google 电子表格交互,但是当令牌过期时,我不知道如何刷新它。

我的代码几乎是从https://developers.google.com/sheets/api/quickstart/python复制的:

from __future__ import print_function
import os.path
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials

def service_spread():
    """
    Creates token for spreadsheet with required authorisation.
    Returns required service.
    """
    SCOPES = ['https://www.googleapis.com/auth/spreadsheets']
    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.
    if os.path.exists('token_spread.json'):
        creds = Credentials.from_authorized_user_file('token_spread.json', SCOPES)
    # If there are no (valid) credentials available, let the user log in.
    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
            creds.refresh(Request())
        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_spread.json', 'w') as token:
            token.write(creds.to_json())

    return build('sheets', 'v4', credentials=creds)

如果没有代币,它的作用就像一个符咒。如果存在令牌并且已过期,则会引发以下错误:

RefreshError                              Traceback (most recent call last)
<ipython-input-6-63b097a471a1> in <module>
----> 1 service = service_spread()

<ipython-input-5-12e029dbbb2f> in service_spread()
     14     if not creds or not creds.valid:
     15         if creds and creds.expired and creds.refresh_token:
---> 16             creds.refresh(Request())
     17         else:
     18             flow = InstalledAppFlow.from_client_secrets_file('credentials.json', SCOPES)

~\anaconda3\lib\site-packages\google\oauth2\credentials.py in refresh(self, request)
    206         scopes = self._scopes if self._scopes is not None else self._default_scopes
    207 
--> 208         access_token, refresh_token, expiry, grant_response = _client.refresh_grant(
    209             request,
    210             self._token_uri,

~\anaconda3\lib\site-packages\google\oauth2\_client.py in refresh_grant(request, token_uri, refresh_token, client_id, client_secret, scopes)
    246         body["scope"] = " ".join(scopes)
    247 
--> 248     response_data = _token_endpoint_request(request, token_uri, body)
    249 
    250     try:

~\anaconda3\lib\site-packages\google\oauth2\_client.py in _token_endpoint_request(request, token_uri, body)
    122                 retry += 1
    123                 continue
--> 124             _handle_error_response(response_body)
    125 
    126     return response_data

~\anaconda3\lib\site-packages\google\oauth2\_client.py in _handle_error_response(response_body)
     58         error_details = response_body
     59 
---> 60     raise exceptions.RefreshError(error_details, response_body)
     61 
     62 

RefreshError: ('invalid_scope: Bad Request', '{\n  "error": "invalid_scope",\n  "error_description": "Bad Request"\n}')

我在网上查遍了,但不知道如何解决。有人可以帮助我吗?我需要此代码在无人监督的情况下运行,因此我需要自动刷新令牌,无需任何人为干预。

google-api google-oauth google-sheets-api python-3.8 google-api-python-client
1个回答
0
投票

我偶然发现了这个,我也遇到了同样的问题并修复了它。他们检查令牌是否过期的逻辑一定有问题。但我添加了手动检查来做到这一点。在

token.json
中有一个
expiry
字段,显示令牌将在何时过期。我只是手动检查当前时间是否超过该时间。如果是这样,我自己删除该文件。我的验证码如下。

    def auth(self):
        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.
        if os.path.exists("token.json"):
            token = json.load(open("token.json"))
            expiry = datetime.fromisoformat(token["expiry"])
            if expiry < datetime.now(expiry.tzinfo):
                self.logger.info(
                    "Token expired, removing token.json and re-authenticating"
                )
                os.remove("token.json")
                creds = None
            else:
                self.logger.info("Reading credentials from existing token.json")
                creds = Credentials.from_authorized_user_file("token.json", SCOPES)
        # If there are no (valid) credentials available, let the user log in.
        if not creds or not creds.valid:
            if creds and creds.expired and creds.refresh_token:
                self.logger.info("Credentials expired, sending refresh request")
                creds.refresh(Request())
            else:
                self.logger.info(
                    "Credentials not found, sending auth request to local server"
                )
                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:
                self.logger.info("Saving credentials to token.json")
                token.write(creds.to_json())
        self.service = build("gmail", "v1", credentials=creds)
        self.logger.info("Completed Gmail authentication flow")
© www.soinside.com 2019 - 2024. All rights reserved.