如何使用访问和刷新令牌返回自定义数据以识别 Django Rest Framework 简单 JWT 中的用户?

Posted

技术标签:

【中文标题】如何使用访问和刷新令牌返回自定义数据以识别 Django Rest Framework 简单 JWT 中的用户?【英文标题】:How to return custom data with Access and Refresh Tokens to identify users in Django Rest Framework simple JWT? 【发布时间】:2019-04-28 01:52:15 【问题描述】:

在 Django 中,超级用户可以根据他们的滚动添加更多用户。我正在使用带有 DRF 的简单 JWT 进行身份验证。但是仅通过查看访问令牌和刷新令牌是不可能检测到用户类型的。

这是我的 settings.py 文件

REST_FRAMEWORK = 
    'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.IsAuthenticated',),
    'DEFAULT_AUTHENTICATION_CLASSES': ('rest_framework_simplejwt.authentication.JWTAuthentication',),



urls.py

from django.contrib import admin
from django.urls import path, include
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView


urlpatterns = [

    path('admin/', admin.site.urls),
    path('', include('Manage_Merchants.urls')),

    path('api-auth', include('rest_framework.urls')),
    path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
    path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),


]

当我通过 Postman 访问 127.0.0.1:8000/api/token/ 时,它会询问用户名和密码。当我输入用户名和密码时,它会生成一个刷新和访问令牌。 Generate JWT with DRF using Postman

那么我如何识别令牌是为超级用户或其他用户创建的超级用户生成的?如何将更多值作为字典与访问和刷新令牌一起传递以识别用户类型?

【问题讨论】:

【参考方案1】:

djangorestframework-simplejwt==4.4.0 版本中是方法 validate 而不是 to_representation,意思是:

在您的 serializer.py 中,您需要覆盖 TokenObtainPairSerializer 以便在响应中包含您要发送的所有数据

from rest_framework_simplejwt.serializers import TokenObtainPairSerializer


class CustomTokenObtainPairSerializer(TokenObtainPairSerializer):
    def validate(self, attrs):
        # The default result (access/refresh tokens)
        data = super(CustomTokenObtainPairSerializer, self).validate(attrs)
        # Custom data you want to include
        data.update('user': self.user.username)
        data.update('id': self.user.id)
        # and everything else you want to send in the response
        return data

现在在您的views.py 中,您需要覆盖 TokenObtainPairView 以便将其与新的序列化程序配对。

from .serializers import CustomTokenObtainPairSerializer


class CustomTokenObtainPairView(TokenObtainPairView):
    # Replace the serializer with your custom
    serializer_class = CustomTokenObtainPairSerializer

现在将它映射到您的url.py

from rest_framework_simplejwt.views import TokenRefreshView, TokenVerifyView
from . import views

urlpatterns = [
    # This one now has the custom view mapped with the custom serializer that includes the desired data
    path('token/', views.CustomTokenObtainPairView.as_view(), name='token_obtain_pair'),
    path('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
    path('token/verify/', TokenVerifyView.as_view(), name='token_verify')
]

【讨论】:

我在视图中收到一条错误消息,指出必须返回响应。我错过了什么吗? 你能分享一下你正在使用的包的堆栈跟踪、视图和版本吗? 我还没有尝试过,但这似乎是我需要的信息。我能问一下你是怎么发现这个的吗?我浏览了文档。如果他们留下一些不足之处。你只需要看看源代码吗? 我通过挖掘 github repo 发现了这一点,但通常它会记录更多。也许我会做一个 PR 并添加到文档中,除非它已经记录在案? @Hanzy 我不是 100% 确定,但我知道 Official Docs,SimpleIsBetternThanComplex 上的博客,大量的谷歌搜索和 Ionic 教程,我正在做一些如何给出一些想法。【参考方案2】:

就像 kumar 说的,你应该重写 TokenObtainPairView。让我更深入地了解它:

在您的核心应用程序views.py 中创建一个新的classView,或者如果您想要更简洁的代码,您可以创建一个新应用程序,例如名为jwt_token_patched 并在其中创建一个views.py 文件。现在添加以下代码:

class TokenObtainPairPatchedView(TokenObtainPairView):
    """
    Takes a set of user credentials and returns an access and refresh JSON web
    token pair to prove the authentication of those credentials.
    """
    serializer_class = serializers.TokenObtainPairPatchedSerializer

    token_obtain_pair = TokenObtainPairView.as_view()

现在为序列化程序添加这个:

class TokenObtainPairPatchedSerializer(TokenObtainPairSerializer):
     def to_representation(self, instance):
         r = super(TokenObtainPairPatchedSerializer, self).to_representation(instance)
         r.update('user': self.user.username)
         return r

方法 to_representation() 在序列化程序以 json 格式返回数据时被调用,因此您可以在其中添加任何您想要的内容。请记住,我只是将用户名放在用户字段值中,您可以在其中添加您想要的用户的任何项目值。

还为此创建一个 url,从现在开始使用该方法获取令牌。 如果您愿意,请随时提出任何问题。希望有用:)

【讨论】:

兄弟,我是一个绝对的初学者。我无法正确遵循您的指示。如果您编辑我的代码以便我可以看到用户名和访问令牌,我将非常高兴。从这里克隆我的代码:github.com/SabitDeepto/DRF.git 一个好的答案还应该包括运行代码所需的导入。【参考方案3】:

对于自定义刷新令牌,您可以做的最好的事情是覆盖下面显示的“TokenRefreshSerializer”。但是,如果您想从模型中获取任何字段,我们必须解码令牌以获取用户的 UUID。这可以使用 token_backend 来完成

注意:请确保您使用的是“rest_framework_simplejwt”而不是“djangorestframework-jwt”,因为它已被弃用

from rest_framework_simplejwt.serializers import TokenRefreshSerializer
from rest_framework_simplejwt.state import token_backend

class CustomTokenRefreshSerializer(TokenRefreshSerializer):
    def validate(self, attrs):
        data = super(CustomTokenRefreshSerializer, self).validate(attrs)
        decoded_payload = token_backend.decode(data['access'], verify=True)
        user_uid=decoded_payload['user_id']
        # add filter query
        data.update('custom_field': 'custom_data'))
        return data

然后使用继承“TokenRefreshView”的“CustomTokenRefreshView”这个序列化器,如下所示

from rest_framework_simplejwt.views import TokenRefreshView
class CustomTokenRefreshView(TokenRefreshView):
    """
    Custom Refresh token View
    """
    serializer_class = CustomTokenRefreshSerializer

并将其添加到网址中

path('api/token/refresh/', CustomTokenRefreshView.as_view(), name='token_refresh'),

【讨论】:

以上是关于如何使用访问和刷新令牌返回自定义数据以识别 Django Rest Framework 简单 JWT 中的用户?的主要内容,如果未能解决你的问题,请参考以下文章

如何以管理员用户身份撤销用户的访问令牌和刷新令牌?在 Oauth2 中使用 JWT

如何识别 OAuth 令牌是不是已过期?

使用 Apple 登录刷新令牌验证仅返回访问令牌

如何使用刷新令牌更新访问令牌?

如何使用 laravel 护照自定义访问令牌

Azure API 管理 - 如何刷新访问令牌后端 API?