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

15
在Django中,超级用户可以根据它们的角色添加更多用户。我正在使用DRF的简单JWT进行身份验证。但仅通过查看Access和Refresh Tokens无法检测用户类型。
以下是我的settings.py文件。

In Django,超级用户可以根据其角色添加更多用户。我正在使用DRF的简单JWT进行身份验证。但是只凭访问和刷新令牌无法检测用户类型。

这是我的settings.py文件

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


}

urls.py

->

网址(URL).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/时,它会要求输入用户名和密码。当我输入用户名和密码后,它会生成刷新令牌和访问令牌。

那么,我如何确定该令牌是为超级用户还是由超级用户创建的其他用户生成的?如何通过将更多的值作为字典与访问和刷新令牌一起传递来标识用户的类型?

使用Postman生成DRF JWT

4个回答

25
在版本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')
]


1
我在视图中遇到了一个错误,说必须返回一个Response。我有什么遗漏吗? - kingJulian
你能分享一下堆栈跟踪、视图和你正在使用的软件包版本吗? - Emmanuel Valdez
我还没有尝试过,但这似乎是我需要的信息。我可以问一下,你是怎么发现这个的?我也查看了文档,如果它们有所不足的话。你是只能查看源代码吗? - Hanzy
我通过挖掘github仓库找到了这个,但通常会有更详细的文档。除非已经有文档,否则我可以发起PR并添加到文档中。 - Hanzy
1
@Hanzy 我不是100%确定,但我知道官方文档,还有SimpleIsBetterThanComplex的博客,以及大量的谷歌搜索和我正在做的Ionic教程,这些都给了我一些想法。 - Emmanuel Valdez

10

像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

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

此外,为此创建一个 URL,并从现在开始使用该方法获取令牌。 如果您有任何疑问,请随时问。希望这很有用:)


兄弟,我是一个绝对的初学者。我无法正确地按照你的指示进行操作。如果您能编辑我的代码,让我能够看到用户名和访问令牌,我将非常高兴。从这里克隆我的代码:https://github.com/SabitDeepto/DRF.git - deepto
一个好的答案还应该包括运行代码所需的导入。 - Silidrone

2
定制刷新令牌的最佳方法是覆盖下面显示的“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

并在urls中添加以下内容

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

0
使用rest_framework_simplejwt的TokenObtainPairSerializer时,如果要将用户模型中的自定义数据添加到访问令牌中,您可以创建一个继承自TokenObtainPairSerializer的自定义序列化器,并重写其validate方法以在令牌负载中包含自定义数据。
以下是一个示例,展示了如何实现这一点:
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from rest_framework import serializers

class CustomTokenObtainPairSerializer(TokenObtainPairSerializer):
    def validate(self, attrs):
        data = super().validate(attrs)
        
        # Add custom data from your user model here
        user = self.user
        data['user_id'] = user.id
        data['user_username'] = user.username
        # Add more custom data fields as needed
        
        return data

在这个例子中,我们创建了一个名为CustomTokenObtainPairSerializer的自定义序列化器,它继承自TokenObtainPairSerializer。我们重写了validate方法,该方法负责验证用户凭据并生成令牌,以在响应中包含自定义数据。
您可以根据需要将任何自定义数据从用户模型添加到数据字典中。在这个例子中,我们添加了用户的ID和用户名,但您也可以根据需要包含其他自定义数据字段。
然后,您可以在身份验证视图中使用您的自定义序列化器。例如,在您希望获取令牌的视图或视图集中,您可以指定您的自定义序列化器:
from rest_framework_simplejwt.views import TokenObtainPairView

class CustomTokenObtainPairView(TokenObtainPairView):
    serializer_class = CustomTokenObtainPairSerializer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接