InstalledAppFlow run_local_server 离线时挂起

发布于 2025-01-15 19:35:02 字数 458 浏览 4 评论 0原文

我正在将 InstalledAppFlow 用于这样的应用程序

from google_auth_oauthlib.flow import InstalledAppFlow

flow = InstalledAppFlow.from_client_secrets_file(client_secret, scopes=SCOPES)

flow.run_local_server()

,但我遇到的问题是,如果我的应用程序离线(有时会这样),则 flow.run_local_server()只是永远挂起。网页出错,但 flow.run_local_server() 永远不会返回或引发错误。当我的应用程序离线时,它只需要跳过此操作并继续,但我找不到任何方法使其超时、抛出错误或返回。我是否需要传递一个 kwarg 到此或其他方式来进行身份验证,让我可以控制它?

I am using InstalledAppFlow for an application like so

from google_auth_oauthlib.flow import InstalledAppFlow

flow = InstalledAppFlow.from_client_secrets_file(client_secret, scopes=SCOPES)

flow.run_local_server()

But the problem that I have is that if my application is offline (as it will be at times) then flow.run_local_server() just hangs forever. The webpage errors out, but flow.run_local_server() never returns or throws an error. When my application is offline it just needs to skip this and move on, but I can't find any way to cause this to timeout, throw an error, or return. Is there a kwarg I need to pass to this or another way to authenticate that will let me control this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

森林很绿却致人迷途 2025-01-22 19:35:02

作为我所理解的身份验证过程的快速总结。

  1. 首先,用户被引导至实际登录的 GCP 授权页面。
  2. 在此登录后,它们将被重定向到由 flow.run_local_server() 设置的本地服务器。这就是凭据实际传递到应用程序的方式,而不需要用户复制粘贴。
  3. 用户重定向到本地服务器后,凭据将被传递,本地服务器将关闭,应用程序的其余部分可以恢复。

离线的问题是用户无法访问 GCP 页面,因此他们也永远不会重定向到本地页面。因此,本地服务器从未收到请求,因此它不会关闭,这意味着它将继续永远等待该请求。

我的解决方案确实感觉相当老套,即将 flow.run_local_server() 移动到单独的线程。这仍然不会关闭本地服务器,因此它将继续挂起,但在 thread.join(TIMEOUT) 向本地服务器发出请求后,它会收到请求并关闭(在过程,但我们可以捕获并处理它)。

from threading import Thread
import requests
from google_auth_oauthlib.flow import InstalledAppFlow

host = 'localhost'
port = 8080

flow = InstalledAppFlow.from_client_secrets(client_secret, scopes=SCOPES)

def run_local_server():
    try:
        flow.run_local_server(host, port)
    except Exception:
        pass  # Just ignore any errors

thread = Thread(target=run_local_server)
thread.start()
thread.join(90)
if thread.is_alive():
    requests.get(f'http://{host}:{port}/')

请注意,在尝试访问 flow.credentials 时我们仍然需要处理错误,因为如果我们手动终止本地服务器,这些错误将不会被填充,但至少这是一个可以捕获和处理的错误。
这里的另一个考虑因素是,使用 thread.join(TIMEOUT) 这意味着用户现在只有 TIMEOUT 秒的时间来登录,但通常此过程只需要花费几秒钟秒,因此将其设置为 90 秒可能就足够了,但当然值得注意。

As a quick summary of the authentication process as I understand it.

  1. First the user is directed to the GCP authorization page where they actually login.
  2. After logging in here they are redirected to the local server set up by flow.run_local_server(). This is how the credentials is actually passed to the application without requiring the user to copy-paste.
  3. After the user is redirected to the local server the credentials are passed, the local server closes and the rest of the application can resume.

The problem with being offline is that the user can't access the GCP page so they are never redirected to the local page either. Because of this the local server never received a request so it doesn't close which means that it will continue to wait for that request forever.

My solution, which admittedly feels rather hacky, is to move flow.run_local_server() to a separate thread. This still won't close the local server so it will continue to hang, but after thread.join(TIMEOUT) make a request to the local server so that it gets its request and closes (erroring in the process, but we can catch and handle that).

from threading import Thread
import requests
from google_auth_oauthlib.flow import InstalledAppFlow

host = 'localhost'
port = 8080

flow = InstalledAppFlow.from_client_secrets(client_secret, scopes=SCOPES)

def run_local_server():
    try:
        flow.run_local_server(host, port)
    except Exception:
        pass  # Just ignore any errors

thread = Thread(target=run_local_server)
thread.start()
thread.join(90)
if thread.is_alive():
    requests.get(f'http://{host}:{port}/')

Note that we still need to handle errors when trying to access flow.credentials because those won't be populated if we manually killed the local server, but at least that is an error that can be caught and handled.
The other consideration here is that with thread.join(TIMEOUT) that means that the user now only has TIMEOUT seconds to sign in, but typically this process should only take a few seconds so setting this to like 90 seconds should probably be adequate, but certainly worth being aware of.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文