如何检测Google OAuth及Gmail API登录流程中的用户授权取消
如何在Gmail API登录流程中检测用户取消操作
当调用flow.run_local_server(port=0)引导用户登录时,若用户关闭浏览器标签页或点击授权页面的"取消"按钮,脚本会持续等待无法感知取消操作。以下是具体的解决方案:
核心思路
run_local_server在用户主动取消授权时会抛出google.auth.exceptions.FlowError,浏览器意外关闭则会触发连接中断类异常。通过捕获这些异常并设置超时时间,即可及时判定用户取消了登录流程。
修改后的代码示例
from __future__ import print_function import os.path from google.auth.transport.requests import Request from google.oauth2.credentials import Credentials from google_auth_oauthlib.flow import InstalledAppFlow from googleapiclient.discovery import build from googleapiclient.errors import HttpError # 导入需要捕获的异常类 from google.auth.exceptions import FlowError import socket # 修改权限范围后请删除token.json文件 SCOPES = ['https://www.googleapis.com/auth/gmail.readonly'] def main(): """Gmail API基础用法示例:列出用户的邮件标签""" creds = None # token.json存储用户的访问令牌和刷新令牌,首次授权完成后自动创建 if os.path.exists('token.json'): creds = Credentials.from_authorized_user_file('token.json', SCOPES) # 无有效凭据时引导用户登录 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) try: # 设置超时时间(单位:秒),避免脚本无限等待 creds = flow.run_local_server(port=0, timeout=300) except FlowError as e: # 用户主动点击授权页面的"取消"按钮触发此异常 print(f"用户取消了授权操作: {e}") return except (socket.timeout, ConnectionAbortedError): # 浏览器关闭或连接超时触发此异常 print("登录流程超时或连接中断,用户取消了操作") return # 保存凭据供下次使用 with open('token.json', 'w') as token: token.write(creds.to_json()) try: # 调用Gmail API service = build('gmail', 'v1', credentials=creds) results = service.users().labels().list(userId='me').execute() labels = results.get('labels', []) if not labels: print('未找到任何邮件标签。') return print('邮件标签:') for label in labels: print(label['name']) except HttpError as error: # 开发者可在此处理Gmail API的错误 print(f"发生错误: {error}") if __name__ == '__main__': main()
关键说明
- 捕获
FlowError:用户在Google授权页面点击"Cancel"按钮时,会直接抛出该异常,明确标识用户主动取消授权。 - 设置
timeout参数:run_local_server支持timeout参数(单位为秒),超过指定时间未完成授权则触发超时异常,避免脚本无限挂起。 - 捕获连接类异常:用户直接关闭浏览器标签页时,本地服务器会收到连接中断信号,触发
ConnectionAbortedError或socket.timeout,此时可判定用户取消了操作。
内容的提问来源于stack exchange,提问作者M.L.
相关产品推荐
相关产品推荐

