【问题标题】:Detecting when Google API's oAuth token has been revoked检测 Google API 的 oAuth 令牌何时被撤销
【发布时间】:2020-02-02 01:55:47
【问题描述】:

我在这里使用 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-except 块中,以防脚本的第一部分无法检测到令牌被撤销,这似乎很愚蠢。

有没有办法在我实际尝试使用证书之前检测到证书已被吊销?为什么 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:
    ...
...

在检查凭据是否有效的代码之后。有点像最后的检查。这可行,但似乎有点脏,因为它需要额外调用 Google API 服务器,并且基本上正是我上面所说的 - 将第一次执行放在 try-except 块中。有没有更好的办法?

【问题讨论】:

标签: python-3.x oauth oauth-2.0 google-api google-oauth


【解决方案1】:

快速入门适用于使用您自己的凭据的简单案例。他们显然不希望您撤销自己的授权。而不是仅在凭据已过期时才刷新凭据,而是在每次开始时刷新访问令牌。如果刷新令牌已被撤销,则第一次刷新将是失败点。

    # 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)

【讨论】:

  • 如果您不断(或至少偶尔)刷新尚未过期的令牌,Google 的服务器不会将您锁定或锁定吗?
  • 不,您可以创建多少个新刷新令牌有一个速率限制,这取决于应用程序的风险和开发人员的声誉。每个 client_id 的每个用户也有 50 个刷新令牌的硬性限制。如果您调整来自 Google auth 的默认请求,您可以创建仅持续几秒钟的访问令牌,然后您的代码需要运行,这是一个安全奖励
  • 请注意,刷新令牌可能会过期而无需用户直接撤销权限。 developers.google.com/identity/protocols/OAuth2#expiration
  • 所以 50 的硬限制 - 如果您的令牌尚未过期,并且您通过执行 creds.refresh(Request()) 请求另一个令牌,则算作您拥有 2 个活动令牌,超出您的最大值50?原始令牌一到期,您就会回到 50 个活令牌中的 1 个?
  • 限制是 50 个刷新令牌而不是访问令牌。据我所知和测试,访问令牌没有限制(相信我,我在某种程度上强调了他们的身份验证系统,他们因此打电话给我一次,但没有达到访问令牌的限制)
猜你喜欢
  • 2017-06-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多