使用 Django OAuth2 Toolkit 生成单一访问令牌
Posted
技术标签:
【中文标题】使用 Django OAuth2 Toolkit 生成单一访问令牌【英文标题】:Generating single access token with Django OAuth2 Toolkit 【发布时间】:2016-07-22 21:23:49 【问题描述】:我正在使用最新的Django OAuth2 Toolkit (0.10.0) 和 Python 2.7、Django 1.8 和 Django REST framework 3.3
在使用grant_type=password
时,我注意到任何时候用户要求新的访问令牌时都会出现一些奇怪的行为:
curl -X POST -d "grant_type=password&username=<user_name>&password=<password>" -u"<client_id>:<client_secret>" http://localhost:8000/o/token/
新访问令牌和刷新令牌已创建。 旧的访问和刷新令牌在令牌超时之前仍然可用!
我的问题:
我需要的是,每次用户请求新的访问令牌时, 旧的将失效、无法使用并被删除。 另外,有没有一种方法可以使密码 grunt 类型不会创建刷新 令牌。我的应用程序中没有任何用处。我发现的一个解决方案是REST Framework OAuth 一次提供一个访问令牌的配置。我不急于使用该提供程序,但我可能别无选择。
【问题讨论】:
【参考方案1】:如果您想在发布新访问令牌之前删除所有以前的访问令牌,有一个简单的解决方案可以解决这个问题:制作您自己的令牌视图提供者!
下面的代码可能会帮助您实现这种功能:
from oauth2_provider.models import AccessToken, Application
from braces.views import CsrfExemptMixin
from oauth2_provider.views.mixins import OAuthLibMixin
from oauth2_provider.settings import oauth2_settings
class TokenView(APIView, CsrfExemptMixin, OAuthLibMixin):
permission_classes = (permissions.AllowAny,)
server_class = oauth2_settings.OAUTH2_SERVER_CLASS
validator_class = oauth2_settings.OAUTH2_VALIDATOR_CLASS
oauthlib_backend_class = oauth2_settings.OAUTH2_BACKEND_CLASS
def post(self, request):
username = request.POST.get('username')
try:
if username is None:
raise User.DoesNotExist
AccessToken.objects.filter(user=User.objects.get(username=username), application=Application.objects.get(name="Website")).delete()
except Exception as e:
return Response(e.message,status=400)
url, headers, body, status = self.create_token_response(request)
return Response(body, status=status, headers=headers)
您应该注意的部分是 Try-Except 块。在那里我们找到访问令牌并删除它们。在我们创建一个新的之前。
您可以查看如何创建自己的Provider using OAuthLib。 此外,这也可能有用:TokenView in django-oauth-toolkit。您可以在那里看到原始的 Apiview。正如你所说,你正在使用这个包。
至于 refresh_token,正如之前在此处的其他答案中提到的,您不能按照您的要求进行操作。查看oauthlib
密码咕噜类型的代码,你会看到在它的初始化中,refresh_token被设置为True。除非您自己更改 Grunt 类型,否则无法完成。
但是您可以使用访问令牌执行我们上面所做的相同操作。 创建令牌,然后删除刷新令牌。
【讨论】:
我可以使用这种方法完全不需要用户名和密码吗?而是需要应用密码或其他东西。【参考方案2】:我需要的是,每次用户请求新的访问令牌时, 旧的将失效、无法使用并被删除。
当您要求一个新令牌时提供一个新令牌似乎是一种预期的行为。在要求新的之前,您不能revoke现有的吗?
更新
如果您决定只保留一个令牌 - OAuth2Validator 类继承 OAuthLib 的
RequestValidator
并覆盖方法 save_bearer_token。在此方法中,在与AccessToken model 实例创建相关的代码及其 .save() 方法之前,您可以查询(类似于this)以查看数据库中是否已经为该用户保存了一个 AccessToken。如果找到现有的令牌可以从数据库中删除。
我强烈建议将此更改配置为可配置,以防您将来改变主意(在所有多个令牌因this 等原因而发行之后)
更简单的解决方案是拥有自己的验证器类,可能是继承oauth2_provider.oauth2_validators.OAuth2Validator
并覆盖save_bearer_token
的。这个新类应该在settings.py
中为OAUTH2_VALIDATOR_CLASS
提供
另外,有没有一种方法可以使密码 grunt 类型不会创建刷新 令牌。我的应用程序中没有任何用处。
Django OAuth Toolkit 依赖于 OAuthLib。
使 refresh_token 可选归结为BearerToken
oAuthLib 类中的create_token
方法this line 和密码授予类是here。如您所见,此类的__init__
方法采用refresh_token
参数,默认设置为True
。该值用在同一类的create_token_response
方法中
token = token_handler.create_token(request, self.refresh_token)
我相信,Django OAuth 工具包的OAuthLibCore
类中的create_token_response
方法是调用OAuthLib 中相应的create_token_response
的方法。观察 self.server
的用法及其在该类的 __init__
方法中的初始化,该方法仅将验证器作为参数传递,但与 refresh_token
无关。
将此与OAuthLib Imlicit grant type 的create_token_response
方法进行比较,后者显式执行
token = token_handler.create_token(request, refresh_token=False)
根本不创建refresh_token
所以,除非我在这里遗漏了什么,tldr,否则我认为 Django OAuth 工具包不会暴露可选 refresh_token
的特性。
【讨论】:
撤销令牌是我不想提出的请求。这里的目标是在一台机器上只允许一个用户进行一次访问。我不希望同一个用户同时登录到地点。 @Gal 请参阅我的编辑,描述需要在 Django Oauth Toolkit 中完成的更改 我不想更改核心 OAuthLib 类。使用它作为一个包的全部意义在于我不会改变它。另一方面,使用类验证器可能是个好主意。【参考方案3】:接受的答案仍然无法清除 RefreshToken。下面的代码应该撤销刷新和访问令牌。
from oauth2_provider.models import RefreshToken
def clear_token(user):
"""
Clear all user authorized tokens.
"""
for token in RefreshToken.objects.filter(user=user, revoked__isnull=True):
token.revoke()
【讨论】:
【参考方案4】:这是一个直接制作的例子:
from oauthlib.common import generate_token
from oauth2_provider.models import AccessToken, Application
from django.utils import timezone
from dateutil.relativedelta import relativedeltatok = generate_token()
tok = generate_token()
app = Application.objects.first9)
user = User.objects.first()
access_token = AccessToken.objects.create(user=user, application=app, expires=timezone.now() + relativedelta(hours=1), token=tok)
【讨论】:
以上是关于使用 Django OAuth2 Toolkit 生成单一访问令牌的主要内容,如果未能解决你的问题,请参考以下文章
如何从 django-oauth-toolkit 令牌获取当前登录用户?
如何使用刷新令牌在 django-oauth-toolkit 上获取新的访问令牌?
如何使用刷新令牌在 django-oauth-toolkit 上获取新的访问令牌?
Swift Alamofire 上的 Django oauth2 令牌请求失败