通过python的Google API出现长期超时问题?

时间:2018-10-26 15:35:36

标签: django google-api google-oauth django-allauth google-python-api

我正在开发一个小型Web应用程序,以帮助我管理我的Gmail。我已使用通过django-allauth收到的OAuth令牌通过Google的API使用以下功能对其进行了设置。

import google.oauth2.credentials
from .choices import GMAIL
from allauth.socialaccount.models import SocialToken, SocialAccount
from apiclient.discovery import build


def get_credentials(user):
    account = SocialAccount.objects.get(user=user.id)
    token = SocialToken.objects.get(app=GMAIL, account=account).token
    credentials = google.oauth2.credentials.Credentials(token)
    service = build('gmail', 'v1', credentials=credentials)
    return service

这似乎有时可行,但是不幸的是,它不是很可靠。它在build()函数中经常超时,只有大约三分之一的时间成功。我想知道是什么原因导致这种行为,以及是否有更可靠的方法来访问API?

我从these docs找到了以下AuthorizedSession类:

from google.auth.transport.requests import AuthorizedSession

authed_session = AuthorizedSession(credentials)

response = authed_session.request(
    'GET', 'https://www.googleapis.com/storage/v1/b')

但是我不知道如何将其转换为与Google API兼容的对象:

def get_labels(user):
    service = get_credentials(user)
    results = service.users().labels().list(userId='me').execute()
    labels = results.get('labels', [])
    return labels

不幸的是,Google's docs建议使用我希望避免使用的已弃用的软件包。

这是我第一次真正使用OAuth强制执行的API。有人有什么建议吗?

编辑:我尝试从Macbook发布。我也在Windows机器上尝试了该命令,在该机器上它的工作更加一致,但是每次执行build()大约需要20秒。我觉得我做错了。

1 个答案:

答案 0 :(得分:0)

在我终于将刷新令牌添加到组合中之后,今天上午的工作情况要好得多。也许缺席在另一端引起了一些问题。我将继续测试,但现在一切正常:

这是我的完整解决方案:

import google.oauth2.credentials
from google.auth.transport.requests import Request

from apiclient import errors, discovery

from myproject.settings import GMAIL_CLIENT_API_KEY, GMAIL_CLIENT_API_SECRET


def get_credentials(user):
    token_set = user.socialaccount_set.first().socialtoken_set.first()
    token = token_set.token
    refresh_token = token_set.token_secret
    credentials = google.oauth2.credentials.Credentials(
        token,
        refresh_token=refresh_token,
        client_id=GMAIL_CLIENT_API_KEY,
        client_secret=GMAIL_CLIENT_API_SECRET,
        token_uri= google.oauth2.credentials._GOOGLE_OAUTH2_TOKEN_ENDPOINT,
    )

    if credentials.expired:
        request = Request()
        credentials.refresh(request)

    service = discovery.build('gmail', 'v1', credentials=credentials)
    return service

如您所见,我将我的API密钥添加到了设置文件中,并在此处引用了它们。昨天在源文件中打听时,我偶然发现了token_urirefresh_token是花费时间最长的作品。

好消息是django-allauth将把刷新令牌保存到SocialToken列下的token_secret模型中。但是,只有在您的设置中有以下内容时,它才会这样做:

SOCIALACCOUNT_PROVIDERS = {
    'google': {
        'SCOPE': [
            'profile',
            'email',
            'https://www.googleapis.com/auth/gmail.labels',
            'https://www.googleapis.com/auth/gmail.modify'
        ],
        'AUTH_PARAMS': {
            'access_type': 'offline',
        }
    }
}

具体地说,必须将access_type中的AUTH_PARAMS设置为'offline' according to the docs

现在,如果在实施此更改之前连接了帐户,仍然会给您带来麻烦,因此,您还需要通过Google permissions撤消对应用程序的访问权限以获得新的刷新令牌。有关更多信息,请参见in this question

我不确定这是否是正确的/预期的方法,但是直到Google更新Django的文档之前,这种方法至少应该用于测试目的。