我认为这主要是关于最佳做法的问题。
我有一个OAUTH2提供程序,只要刷新令牌就会发出访问令牌(有效期为10小时)。
我发现here刷新访问令牌非常容易,但我无法理解如何决定何时刷新。
简单的答案可能是“当它不再起作用时”,这意味着当我从后端获得HTTP 401时。 这个解决方案的问题在于效率不高,而且我只能假设因为令牌已过期而得到401。
我的django应用程序我发现user social auth
有Extra data
字段,其中包含以下内容:
{
"scope": "read write",
"expires": 36000,
"refresh_token": "xxxxxxxxxxxxx",
"access_token": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"token_type": "Bearer"
}
但我不确定如何使用expires
字段。
所以我的问题是:如何知道访问令牌是否已过期而我需要刷新它?
修改: 我刚刚找到了似乎相关的this comment,但我无法理解如何在管道中插入这个新函数以便在令牌刷新期间工作。
答案 0 :(得分:3)
我最终想出来了。 我最初感到困惑的原因是因为实际上有两种情况:
refresh_token
解决第一种情况
我为管道创建了一个新函数:
def set_last_update(details, *args, **kwargs): # pylint: disable=unused-argument
"""
Pipeline function to add extra information about when the social auth
profile has been updated.
Args:
details (dict): dictionary of informations about the user
Returns:
dict: updated details dictionary
"""
details['updated_at'] = datetime.utcnow().timestamp()
return details
在设置中我将其添加到load_extra_data
SOCIAL_AUTH_PIPELINE = (
'social.pipeline.social_auth.social_details',
'social.pipeline.social_auth.social_uid',
'social.pipeline.social_auth.auth_allowed',
'social.pipeline.social_auth.social_user',
'social.pipeline.user.get_username',
'social.pipeline.user.create_user',
'social.pipeline.social_auth.associate_user',
# the following custom pipeline func goes before load_extra_data
'backends.pipeline_api.set_last_update',
'social.pipeline.social_auth.load_extra_data',
'social.pipeline.user.user_details',
'backends.pipeline_api.update_profile_from_edx',
'backends.pipeline_api.update_from_linkedin',
)
并且,仍然在设置中我在额外数据中添加了新字段。
SOCIAL_AUTH_EDXORG_EXTRA_DATA = ['updated_at']
对于第二种情况:
我覆盖了后端的refresh_token
方法以添加额外的字段。
def refresh_token(self, token, *args, **kwargs):
"""
Overridden method to add extra info during refresh token.
Args:
token (str): valid refresh token
Returns:
dict of information about the user
"""
response = super(EdxOrgOAuth2, self).refresh_token(token, *args, **kwargs)
response['updated_at'] = datetime.utcnow().timestamp()
return response
仍然在后端课程中,我添加了一个额外的字段来提取来自服务器的expires_in
字段。
EXTRA_DATA = [
('refresh_token', 'refresh_token', True),
('expires_in', 'expires_in'),
('token_type', 'token_type', True),
('scope', 'scope'),
]
此时我有创建访问令牌的时间戳(updated_at
)及其有效的秒数(expires_in
)。
注意:updated_at
是近似值,因为它是在客户端而不是在提供者服务器上创建的。
现在唯一缺少的是检查是否需要刷新访问令牌的功能。
def _send_refresh_request(user_social):
"""
Private function that refresh an user access token
"""
strategy = load_strategy()
try:
user_social.refresh_token(strategy)
except HTTPError as exc:
if exc.response.status_code in (400, 401,):
raise InvalidCredentialStored(
message='Received a {} status code from the OAUTH server'.format(
exc.response.status_code),
http_status_code=exc.response.status_code
)
raise
def refresh_user_token(user_social):
"""
Utility function to refresh the access token if is (almost) expired
Args:
user_social (UserSocialAuth): a user social auth instance
"""
try:
last_update = datetime.fromtimestamp(user_social.extra_data.get('updated_at'))
expires_in = timedelta(seconds=user_social.extra_data.get('expires_in'))
except TypeError:
_send_refresh_request(user_social)
return
# small error margin of 5 minutes to be safe
error_margin = timedelta(minutes=5)
if datetime.utcnow() - last_update >= expires_in - error_margin:
_send_refresh_request(user_social)
我希望这可以对其他人有所帮助。
答案 1 :(得分:1)
目前,extra_data
字段现在有auth_time
。您可以将此与expires
一起使用,以确定access_token
的有效性:
if (social.extra_data['auth_time'] + social.extra_data['expires'] - 10) <= int(time.time()):
from social_django.utils import load_strategy
strategy = load_strategy()
social.refresh_token(strategy)
额外的“10”秒用于防止在执行进一步代码之前access_token
可能到期的竞争条件。
此问题中提供了更多详细信息:How can I refresh the token with social-auth-app-django?