简体   繁体   English

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

[英]Generating single access token with Django OAuth2 Toolkit

I'm using the latest Django OAuth2 Toolkit (0.10.0) with Python 2.7, Django 1.8 and Django REST framework 3.3我正在使用最新的Django OAuth2 工具包 (0.10.0)和 Python 2.7、Django 1.8 和 Django REST framework 3.3

While using the grant_type=password , I noticed some weird behavior that any time the user asks for a new access token:在使用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/

A new access token and refresh token is created .令牌新的访问和刷新令牌创建 The old access and refresh token are still usable until token timeout!旧的访问和刷新令牌在令牌超时之前仍然可用!

My Issues:我的问题:

  • What I need is that every time a user asks for a new access token, the old one will become invalid, unusable and will be removed.我需要的是,每次用户请求新的访问令牌时,旧的都会失效、无法使用并被删除。
  • Also, is there a way that the password grunt type wont create refresh token.另外,有没有办法让密码 grunt 类型不会创建刷新令牌。 I don't have any use for that in my application.我在我的应用程序中没有任何用处。

One solution I found is that REST Framework OAuth provides a configuration for One Access Token at a time.我发现的一种解决方案是REST Framework OAuth 一次提供一个访问令牌的配置。 I'm not eager to use that provider, but I might wont have a choice.我并不急于使用该提供程序,但我可能别无选择。

If you like to remove all previous access tokens before issuing a new one, there is a simple solution for this problem: Make your own token view provider!如果你想在发布一个新的访问令牌之前删除所有以前的访问令牌,这个问题有一个简单的解决方案:制作你自己的令牌视图提供者!

The code bellow will probably help you to achieve that kind of functionality:下面的代码可能会帮助您实现这种功能:

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)

The part you should notice is the Try-Except block.您应该注意到的部分是 Try-Except 块。 In there we finding the Access tokens and removing them.在那里我们找到访问令牌并删除它们。 All before we creating a new one.在我们创建一个新的之前。

You can look at how to create your own Provider using OAuthLib .您可以查看如何使用 OAuthLib创建您自己的提供程序 Also, this might be useful as well: TokenView in django-oauth-toolkit .此外,这也可能很有用: django-oauth-toolkit 中的 TokenView You can see there the original Apiview.你可以在那里看到原始的 Apiview。 As you said, you were using this package.正如你所说,你正在使用这个包。

As for the refresh_token , as previously mentioned in other answers here, you can't do what you are asking.至于refresh_token ,正如前面其他答案中提到的,你不能做你所要求的。 When looking at the code of oauthlib password grunt type, you will see that in its initialization, refresh_token is set to True.查看oauthlib password grunt类型的代码,会看到在它的初始化中,refresh_token被设置为True。 Unless you change the Grunt type it self, it can't be done.除非您自己更改 Grunt 类型,否则无法完成。

But you can do the same thing we did above with the access tokens.但是你可以用访问令牌做我们上面做的同样的事情。 Create the token and then delete the refresh token.创建令牌,然后删除刷新令牌。

What I need is that every time a user asks for a new access token, the old one will become invalid, unusable and will be removed.我需要的是,每次用户请求新的访问令牌时,旧的都会失效、无法使用并被删除。

Giving a new token when you ask for one seems like an expected behavior.当你要求一个新的令牌时给出一个新的令牌似乎是一种预期的行为。 Is it not possible for you to revoke the existing one before asking for the new one?你不能在要求新的之前撤销现有的吗?

Update更新


If you are determined to keep just one token - The class OAuth2Validator inherits OAuthLib's RequestValidator and overrides the method save_bearer_token . 如果您决定只保留一个令牌 - OAuth2Validator类继承 OAuthLib 的RequestValidator并覆盖方法save_bearer_token In this method before the code related to AccessToken model instance creation and its .save() method you can query (similar to this ) to see if there is already an AccessToken saved in DB for this user. 在此方法中,在与AccessToken 模型实例创建相关的代码及其 .save() 方法之前,您可以查询(类似于)以查看该用户是否已在 DB 中保存了 AccessToken。 If found the existing token can be deleted from database. 如果找到,可以从数据库中删除现有令牌。

I strongly suggest to make this change configurable, in case you change your mind in future (after all multiple tokens are issued for reasons like this )我强烈建议将此更改配置为可配置,以防您将来改变主意(毕竟出于此类原因发布了多个令牌)

A more simpler solution is to have your own validator class, probably one that inherits oauth2_provider.oauth2_validators.OAuth2Validator and overrides save_bearer_token .更简单的解决方案是拥有自己的验证器类,可能是继承oauth2_provider.oauth2_validators.OAuth2Validator并覆盖save_bearer_token This new class should be given for OAUTH2_VALIDATOR_CLASS in settings.py应该在settings.pyOAUTH2_VALIDATOR_CLASS提供这个新类


Also, is there a way that the password grunt type wont create refresh token.另外,有没有办法让密码 grunt 类型不会创建刷新令牌。 I don't have any use for that in my application.我在我的应用程序中没有任何用处。

Django OAuth Toolkit depends on OAuthLib. Django OAuth 工具包依赖于 OAuthLib。

Making refresh_token optional boils down to create_token method in BearerToken class of oAuthLib at this line and the class for password grant is here .使refresh_token 可选归结为这一行BearerToken类中的create_token方法,密码授予类在这里 As you can see the __init__ method for this class takes refresh_token argument which by default is set to True .如您所见,此类的__init__方法采用refresh_token参数,该参数默认设置为True This value is used in create_token_response method of the same class at the line该值用于同一类的create_token_response方法中

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

create_token_response method in OAuthLibCore class of Django OAuth toolkit is the one, I believe, calls the corresponding create_token_response in OAuthLib.我相信,Django OAuth 工具包的OAuthLibCore类中的create_token_response方法就是调用 OAuthLib 中相应的create_token_response方法。 Observe the usage of self.server and its initialization in __init__ method of this class, which has just the validator passed as an argument but nothing related to refresh_token .观察self.server的用法及其在此类的__init__方法中的初始化,该方法仅将验证器作为参数传递,但与refresh_token无关。

Compare this with OAuthLib Imlicit grant type 's create_token_response method, which explicitly does将此与OAuthLib Imlicit grant typecreate_token_response方法进行比较,该方法明确执行

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

to not create refresh_token at all根本不创建refresh_token

So, unless I missed something here, tldr , I don't think Django OAuth toolkit exposes the feature of optional refresh_token .所以,除非我在这里遗漏了一些东西, tldr ,我认为 Django OAuth 工具包不会公开可选的refresh_token的功能。

The accepted answer still fails to clear the RefreshToken.接受的答案仍然无法清除 RefreshToken。 Below code should revoke both the refresh and access token.下面的代码应该撤销刷新和访问令牌。

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()

Here's an example of just making it directly:这是一个直接制作的例子:

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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM