使用Django OAuth2 Toolkit生成单一访问令牌

时间:2016-04-03 09:56:48

标签: python django oauth-2.0 django-rest-framework django-oauth

我使用最新的Django OAuth2 Toolkit (0.10.0)与Python 2.7,Django 1.8和Django REST框架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一次为一个访问令牌提供配置。我并不急于使用该提供商,但我可能无法做出选择。

4 个答案:

答案 0 :(得分:13)

如果您想在发布新密码之前删除所有以前的访问权限,可以使用以下方法解决此问题:创建自己的代币视图提供程序!

下面的代码可能会帮助您实现这种功能:

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密码grunt类型的代码时,您会看到在初始化时,refresh_token设置为True。除非你自己更改Grunt类型,否则无法完成。

但是您可以使用访问令牌执行上述操作。 创建令牌,然后删除刷新令牌。

答案 1 :(得分:5)

  

我需要的是每次用户请求新的访问令牌时,   旧的将变为无效,无法使用并将被删除。

当您要求提供新令牌时,似乎是预期的行为。在要求新的revoke之前,您是否不可能OAuth2Validator现有的?

<强>更新

<小时/> 如果您决定只保留一个令牌 - 课程save_bearer_token会继承OAuthLib RequestValidator并覆盖方法AccessToken model。在与this实例创建及其.save()方法相关的代码之前的此方法中,您可以查询(类似于this)以查看是否已为此用户在DB中保存了AccessToken。如果找到,则可以从数据库中删除现有令牌。

我强烈建议您将此更改配置为可配置,以防您日后改变主意(在this line之后发布所有多个令牌之后)

更简单的解决方案是拥有自己的验证器类,可能是继承oauth2_provider.oauth2_validators.OAuth2Validator并覆盖save_bearer_token的验证器类。这个新课程应该在OAUTH2_VALIDATOR_CLASS

中为settings.py提供
  

另外,有没有办法让密码grunt类型不会创建刷新   令牌。在我的申请中,我没有任何用处。

Django OAuth Toolkit依赖于OAuthLib。

使refresh_token可选归结为here的o {{{}}类oAuthLib中的create_token方法,密码授权类为OAuthLibCore。正如您所看到的,此类的BearerToken方法采用__init__参数,默认情况下该参数设置为refresh_token。该值用于

行中同一类的True方法
create_token_response
我相信,OAuthLib Imlicit grant type类Django OAuth工具包中的

token = token_handler.create_token(request, self.refresh_token) 方法会调用OAuthLib中的相应create_token_response。观察create_token_response及其在此类的self.server方法中的初始化的用法,该方法仅将验证器作为参数传递但与__init__无关。

将此与{{3}}的refresh_token方法进行比较,该方法明确地执行

create_token_response

根本不创建token = token_handler.create_token(request, refresh_token=False)

所以,除非我在这里遗漏了一些内容, tldr ,否则我不认为Django OAuth工具包暴露了可选refresh_token的功能。

答案 2 :(得分:0)

接受的答案仍然无法清除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()

答案 3 :(得分:0)

这是一个直接制作的例子:

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)