OAuth 2 工作流程
介绍
以下部分提供了一些示例代码,演示了您可以与 requests-oauthlib 一起使用的一些可能的 OAuth2 流程。我们提供了四个示例:一个用于 OAuth2 RFC 定义的每种授权类型。这些授权类型(或工作流)是授权代码授权(或 Web 应用程序流)、隐式授权(或移动应用程序流)、资源所有者密码凭证授权(或更简洁地说,传统应用程序流)和客户端凭证授予(或后端应用程序流程)。
网络应用程序流程
以下步骤概述了如何使用默认授权授予类型流程来获取访问令牌并获取受保护的资源。在此示例中,提供者是 Google,受保护的资源是用户的个人资料。
- 手动从您的 OAuth 提供商处获取凭据。至少您将需要一个
client_id
但可能还需要一个client_secret
. 在此过程中,您可能还需要注册一个默认重定向 URI,以供您的应用程序使用。将这些内容保存在 Python 脚本中:
>>> client_id = r'your_client_id'
>>> client_secret = r'your_client_secret'
>>> redirect_uri = 'https://your.callback/uri'
- 通过重定向进行用户授权。首先,我们将从提供者提供的基本 URL 和先前获得的凭据创建一个授权 URL。此外,大多数提供商会要求您请求访问特定范围。在此示例中,我们将要求 Google 访问用户的电子邮件地址和用户个人资料。
# Note that these are Google specific scopes
>>> scope = ['https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/userinfo.profile']
>>> oauth = OAuth2Session(client_id, redirect_uri=redirect_uri,
scope=scope)
>>> authorization_url, state = oauth.authorization_url(
'https://accounts.google.com/o/oauth2/auth',
# access_type and prompt are Google specific extra
# parameters.
access_type="offline", prompt="select_account")
>>> print 'Please go to %s and authorize access.' % authorization_url
>>> authorization_response = raw_input('Enter the full callback URL')
- 使用在用户授权期间获得的授权码从提供者处获取访问令牌。
>>> token = oauth.fetch_token(
'https://accounts.google.com/o/oauth2/token',
authorization_response=authorization_response,
# Google specific extra parameter used for client
# authentication
client_secret=client_secret)
- 使用您刚刚获得的访问令牌访问受保护的资源。例如,获取用户个人资料信息。
>>> r = oauth.get('https://www.googleapis.com/oauth2/v1/userinfo')
>>> # Enjoy =)
移动应用流程
以下步骤概述了如何使用隐式代码授予类型流程来获取访问令牌。
- 您将需要以下设置。
>>> client_id = 'your_client_id'
>>> scopes = ['scope_1', 'scope_2']
>>> auth_url = 'https://your.oauth2/auth'
- 获取授权网址
>>> from oauthlib.oauth2 import MobileApplicationClient
>>> from requests_oauthlib import OAuth2Session
>>> oauth = OAuth2Session(client=MobileApplicationClient(client_id=client_id), scope=scopes)
>>> authorization_url, state = oauth.authorization_url(auth_url)
- 从提供程序获取访问令牌。
>>> response = oauth.get(authorization_url)
>>> oauth.token_from_fragment(response.url)
旧版应用程序流程
以下步骤概述了如何使用资源所有者密码凭据授予类型流程来获取访问令牌。
- 您将需要以下设置。
client_secret
是可选的,具体取决于提供者。
>>> client_id = 'your_client_id'
>>> client_secret = 'your_client_secret'
>>> username = 'your_username'
>>> password = 'your_password'
- 从提供程序获取访问令牌。
>>> from oauthlib.oauth2 import LegacyApplicationClient
>>> from requests_oauthlib import OAuth2Session
>>> oauth = OAuth2Session(client=LegacyApplicationClient(client_id=client_id))
>>> token = oauth.fetch_token(token_url='https://somesite.com/oauth2/token',
username=username, password=password, client_id=client_id,
client_secret=client_secret)
后端应用流程
以下步骤概述了如何使用资源所有者客户端凭据授予类型流程来获取访问令牌。
-
从您的 OAuth 提供商处获取凭据。至少你需要一个
client_id
andclient_secret
。>>> client_id = 'your_client_id' >>> client_secret = 'your_client_secret'
-
从提供程序获取访问令牌。
>>> from oauthlib.oauth2 import BackendApplicationClient >>> from requests_oauthlib import OAuth2Session >>> client = BackendApplicationClient(client_id=client_id) >>> oauth = OAuth2Session(client=client) >>> token = oauth.fetch_token(token_url='https://provider.com/oauth2/token', client_id=client_id, client_secret=client_secret)
如果您的提供商要求您在 Basic Auth 标头中传递身份验证凭据,您可以这样做:
>>> from oauthlib.oauth2 import BackendApplicationClient >>> from requests_oauthlib import OAuth2Session >>> from requests.auth import HTTPBasicAuth >>> auth = HTTPBasicAuth(client_id, client_secret) >>> client = BackendApplicationClient(client_id=client_id) >>> oauth = OAuth2Session(client=client) >>> token = oauth.fetch_token(token_url='https://provider.com/oauth2/token', auth=auth)
刷新令牌
某些提供商会为您refresh_token
提供 access_token
. 这些可用于直接获取新的访问令牌,而无需通过正常的 OAuth 工作流程。requests-oauthlib
提供了三种获取刷新令牌的方法。所有这些都取决于您expires_in
在令牌中指定的准确度。
expires_in
是与访问和刷新令牌一起提供的凭据,指示从现在起访问令牌过期的秒数。通常,访问令牌会在一小时后过期,并且expires_in
会是3600
. 如果没有这个,就不可能requests-oauthlib
知道令牌何时过期,因为由于令牌过期而导致请求失败的状态代码没有定义。
如果您对令牌刷新不感兴趣,请始终传递正值expires_in
或完全忽略它。
(ALL) 定义令牌、令牌保护程序和所需的凭据
>>> token = {
... 'access_token': 'eswfld123kjhn1v5423',
... 'refresh_token': 'asdfkljh23490sdf',
... 'token_type': 'Bearer',
... 'expires_in': '-30', # initially 3600, need to be updated by you
... }
>>> client_id = r'foo'
>>> refresh_url = 'https://provider.com/token'
>>> protected_url = 'https://provider.com/secret'
>>> # most providers will ask you for extra credentials to be passed along
>>> # when refreshing tokens, usually for authentication purposes.
>>> extra = {
... 'client_id': client_id,
... 'client_secret': r'potato',
... }
>>> # After updating the token you will most likely want to save it.
>>> def token_saver(token):
... # save token in database / session
(一)在每个请求上定义 Try-Catch TokenExpiredError
这是最基本的版本,当需要刷新但手动完成刷新时会引发错误。
>>> from requests_oauthlib import OAuth2Session
>>> from oauthlib.oauth2 import TokenExpiredError
>>> try:
... client = OAuth2Session(client_id, token=token)
... r = client.get(protected_url)
>>> except TokenExpiredError as e:
... token = client.refresh_token(refresh_url, **extra)
... token_saver(token)
>>> client = OAuth2Session(client_id, token=token)
>>> r = client.get(protected_url)
(二)定义自动令牌刷新自动但手动更新
这是自动刷新令牌的基本和方便刷新方法之间的中间,可以说是尴尬的,但保存新令牌是手动完成的。
>>> from requests_oauthlib import OAuth2Session, TokenUpdated
>>> try:
... client = OAuth2Session(client_id, token=token,
... auto_refresh_kwargs=extra, auto_refresh_url=refresh_url)
... r = client.get(protected_url)
>>> except TokenUpdated as e:
... token_saver(e.token)
(三、推荐)定义自动令牌刷新和更新
第三种也是推荐的方法将自动获取刷新令牌并保存它们。它不需要异常捕获并产生干净的代码。但是请记住,您仍然需要更新expires_in
才能触发刷新。
>>> from requests_oauthlib import OAuth2Session
>>> client = OAuth2Session(client_id, token=token, auto_refresh_url=refresh_url,
... auto_refresh_kwargs=extra, token_updater=token_saver)
>>> r = client.get(protected_url)
TLS 客户端身份验证
要通过自签名或 CA 颁发的证书使用 TLS 客户端身份验证 (draft-ietf-oauth-mtls),请在令牌请求中传递证书并确保在请求中发送客户端 ID:
>>> oauth.fetch_token(token_url='https://somesite.com/oauth2/token',
... include_client_id=True, cert=('test-client.pem', 'test-client-key.pem'))