18

我正在尝试编写一个 Django 应用程序,它在特定的 Google 日历中创建事件。到目前为止,我已经成功了。只有一个小问题:

我不知道如何使用 google python 客户端获取刷新令牌。

结果是,在我的令牌过期后,应用程序无法运行,我必须创建一个新令牌。如果我理解文档正确,那就是刷新令牌的来源。

访问令牌的生命周期有限,在某些情况下,应用程序需要在单个访问令牌的生命周期之外访问 Google API。在这种情况下,您的应用程序可以获得所谓的刷新令牌。刷新令牌允许您的应用程序获取新的访问令牌。

Google 文档(参见“基本步骤”,第 4 节)

我的代码

import gflags
import httplib2

from apiclient.discovery import build
from oauth2client.file import Storage
from oauth2client.client import OAuth2WebServerFlow
from oauth2client.tools import run

FLAGS = gflags.FLAGS

FLOW = OAuth2WebServerFlow(
    client_id=GOOGLE_API_CLIENT_ID,
    client_secret=GOOGLE_API_CLIENT_SECRET,
    scope=GOOGLE_API_CALENDAR_SCOPE,
    user_agent=GOOGLE_API_USER_AGENT)

storage = Storage(GOOGLE_API_CREDENTIAL_PATH)
credentials = storage.get()
if credentials is None or credentials.invalid == True:
  credentials = run(FLOW, storage)

http = httplib2.Http()
http = credentials.authorize(http)

service = build(serviceName='calendar', version='v3', http=http,
   developerKey=GOOGLE_API_DEVELOPER_KEY)

event = {
    [... Dictionary with all the necessary data here ...]
}

created_event = service.events().insert(calendarId=GOOGLE_API_CALENDAR_ID, body=event).execute()

这几乎是 Google 文档中的示例。有趣的是Storage。这是一个保存一些凭证数据的文件。

我的存储文件内容:

{
    "_module": "oauth2client.client", 
    "_class": "OAuth2Credentials", 
    "access_token": [redacted], 
    "token_uri": "https://accounts.google.com/o/oauth2/token", 
    "invalid": true, 
    "client_id": [redacted], 
    "client_secret": [redacted], 
    "token_expiry": "2011-12-17T16:44:15Z", 
    "refresh_token": null, 
    "user_agent": [redacted]
}

那里应该有一个刷新令牌,但它是null。所以我想我可以以某种方式请求刷新令牌

我将不胜感激有关如何使其正常工作的任何帮助。如果您需要更多信息,请告诉我。

4

4 回答 4

19

我不知道如何使用 Python 客户端或日历 API 执行此操作(我只是使用 ruby​​ OAuth2 库来访问联系人 API),但我发现我需要向用户请求“离线”访问权限。

这是通过将值为“offline”的“access_type”参数添加到授权 url(您将用户重定向到单击“我想允许此应用程序获取我的数据”的那个)来完成的。

如果你这样做,当你向谷歌请求访问令牌时,你会在 JSON 响应中得到一个 refresh_token。否则,您只会获得访问令牌(有效期为一小时)。

这个要求显然是最近添加的(可能没有很好的记录)。

您过去无需获得特定的“离线”权限即可获得刷新令牌。

希望这能为您指明正确的方向。

于 2011-12-17T22:19:58.677 回答
14

因此,如果您已经在没有设置的情况下接受了同意access_type='offline',则需要强制用户通过也通过approval_prompt='force'.

self.flow = OAuth2WebServerFlow(
    client_id=self.client_id,
    client_secret=self.client_secret,
    scope=self.SCOPE,
    user_agent=user_agent,
    redirect_uri='urn:ietf:wg:oauth:2.0:oob',
    access_type='offline', # This is the default
    approval_prompt='force'
)

auto然后,您可以在获得刷新令牌后删除强制提示/将其设置为。

于 2013-01-12T00:24:18.090 回答
4

自2017-06-16 起,答案似乎已被弃用。

  • approval_prompt已弃用
  • prompt=force无效

这是一个工作示例:

from oauth2client.client import OAuth2WebServerFlow

flow = OAuth2WebServerFlow(
    client_id=CLIEN_ID,
    client_secret=CLIENT_SECRET,
    scope=SCOPES,
    redirect_uri='http://localhost/gdrive_auth',
    access_type='offline',
    prompt='consent',
)

print(flow.step1_get_authorize_url())
于 2017-06-16T09:26:23.680 回答
0

如果您遵循本手册https://developers.google.com/identity/protocols/OAuth2WebServer并且您无法接收refresh_token,请尝试在此处添加prompt='consent'

authorization_url, state = flow.authorization_url(
    # Enable offline access so that you can refresh an access token without
    # re-prompting the user for permission. Recommended for web server apps.
    access_type='offline',
    prompt='consent',
    # Enable incremental authorization. Recommended as a best practice.
    include_granted_scopes='true')

这里描述了为什么会发生

于 2018-08-18T16:23:36.143 回答