15

我正在使用最新的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/

创建一个的访问令牌和刷新令牌。在令牌超时之前,的访问和刷新令牌仍然可用!

我的问题:

  • 我需要的是,每次用户请求新的访问令牌时,旧的访问令牌都会变得无效、无法使用并被删除。
  • 此外,有没有办法让密码咕噜声类型不会创建刷新令牌。我在我的应用程序中没有任何用处。

我发现的一种解决方案是REST Framework OAuth一次提供一个访问令牌的配置。我不急于使用该提供商,但我可能别无选择。

4

4 回答 4

20

如果您想在发布新的访问令牌之前删除所有以前的访问令牌,有一个简单的解决方案来解决这个问题:制作您自己的令牌视图提供程序!

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

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 块。在那里我们找到访问令牌并删除它们。在我们创建一个新的之前。

您可以查看如何使用 OAuthLib创建自己的Provider 。此外,这也可能有用:TokenView in django-oauth-toolkit。您可以在那里看到原始的 Apiview。正如你所说,你正在使用这个包。

至于refresh_token,正如之前在此处的其他答案中提到的那样,您不能按照您的要求进行操作。查看oauthlib密码 grunt 类型的代码时,您会看到在其初始化中,refresh_token 设置为 True。除非您自己更改 Grunt 类型,否则无法完成。

但是你可以用访问令牌做我们上面做的同样的事情。创建令牌,然后删除刷新令牌。

于 2016-04-12T09:19:53.470 回答
6

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

当您要求一个新令牌时给出一个新令牌似乎是一种预期的行为。难道你不能在要求新的之前 撤销现有的吗?

更新


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

我强烈建议将此更改配置为可配置,以防您将来改变主意(在所有多个令牌出于此类原因发行之后)

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


此外,有没有办法让密码咕噜声类型不会创建刷新令牌。我在我的应用程序中没有任何用处。

Django OAuth Toolkit 依赖于 OAuthLib。

将 refresh_token 设为可选归结为这一行的 oAuthLib 类中的create_token方法,而密码授予类在此处。如您所见,此类的方法采用默认设置为的参数。该值用于该行的同一类的方法中BearerToken__init__refresh_tokenTruecreate_token_response

token = token_handler.create_token(request, self.refresh_token)

create_token_responseOAuthLibCore我相信,Django OAuth 工具包类中的方法是调用create_token_responseOAuthLib 中相应的方法。观察这个类的方法的用法self.server和它的初始化__init__,它只是将验证器作为参数传递,但与refresh_token.

将此与OAuthLib Imlicit grant typecreate_token_response方法进行比较,该方法明确执行

token = token_handler.create_token(request, refresh_token=False)

refresh_token根本不创造

所以,除非我在这里遗漏了一些东西,tldr ,否则我认为 Django OAuth 工具包不会暴露 optional 的特性refresh_token

于 2016-04-10T10:15:39.487 回答
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()
于 2020-04-19T18:13:32.807 回答
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)
于 2021-06-15T18:04:03.793 回答