【问题标题】:Customizing JWT response from django-rest-framework-simplejwt从 django-rest-framework-simplejwt 自定义 JWT 响应
【发布时间】:2019-06-29 21:29:56
【问题描述】:

我正在设置 Django 以发送 JWT 响应而不是视图。我尝试使用 django-rest-framework-simplejwt。

在这个框架中提供了一个函数TokenObtainPairView.as_view(),它返回一对jwt。我需要用另一个 Json 响应返回访问令牌,而不是提供的两个令牌。

理想情况下,我想要一个 JsonResponse,其中包含与此相同的访问令牌:TokenObtainPairView.as_view()

我尝试创建自己的视图,如下所示。

更新:在 Settings.py 中提供

SIMPLE_JWT = {
    'ACCESS_TOKEN_LIFETIME': timedelta(days=1),
    'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
    'ROTATE_REFRESH_TOKENS': False,
    'BLACKLIST_AFTER_ROTATION': True,

    'ALGORITHM': 'HS256',
    'SIGNING_KEY': SECRET_KEY,
    'VERIFYING_KEY': None,

    'AUTH_HEADER_TYPES': ('Bearer',),
    'USER_ID_FIELD': 'id',
    'USER_ID_CLAIM': 'user_id',

    'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',),
    'TOKEN_TYPE_CLAIM': 'token_type',

    'SLIDING_TOKEN_REFRESH_EXP_CLAIM': 'refresh_exp',
    'SLIDING_TOKEN_LIFETIME': timedelta(days=1),
    'SLIDING_TOKEN_REFRESH_LIFETIME': timedelta(days=1),
}

登录网址路径

urlpatterns = [
    path('auth/', views.LoginView.as_view()),
]

我创建的登录视图

class LoginView(APIView):
    permission_classes = (AllowAny,)

    def post(self, request, *args, **kwargs):
        username = request.data['username']
        password = request.data['password']

        user = authenticate(username=username, password=password)

        if user is not None:
            payload = {
                'user_id': user.id,
                'exp': datetime.now(),
                'token_type': 'access'
            }

            user = {
                'user': username,
                'email': user.email,
                'time': datetime.now().time(),
                'userType': 10
            }

            token = jwt.encode(payload, SECRET_KEY).decode('utf-8')
            return JsonResponse({'success': 'true', 'token': token, 'user': user})

        else:
            return JsonResponse({'success': 'false', 'msg': 'The credentials provided are invalid.'})

框架提供的模式。

urlpatterns = [
...
path('token/', TokenObtainPairView.as_view()),
...
]

它返回这个令牌

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNTQ5NDk3NDQ2LCJqdGkiOiI3YmU4YzkzODE4MWI0MmJlYTFjNDUyNDhkNDZmMzUxYSIsInVzZXJfaWQiOiIwIn0.xvfdrWf26g4FZL2zx3nJPi7tjU6QxPyBjq-vh1fT0Xs P>

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTU0OTQ5NzQ0NiwianRpIjoiOTNhYzkxMjU5NmZkNDYzYjg2OGQ0ZTM2ZjZkMmJhODciLCJ1c2VyX2lkIjoiMCJ9.dOuyuFuMjkVIRI2_UcXT8_alCjlXNaiRJx8ehQDIBCg P>

如果您转到https://jwt.io/,您将看到返回的内容

【问题讨论】:

    标签: json django angular jwt


    【解决方案1】:
    • 例如:通过添加用户名和组来自定义 simpleJWT 响应,

    1. 覆盖TokenObtainPairSerializer 中的validate 方法
    # project/views.py
    
    from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
    from rest_framework_simplejwt.views import TokenObtainPairView
    
    
    class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
        def validate(self, attrs):
            data = super().validate(attrs)
            refresh = self.get_token(self.user)
            data['refresh'] = str(refresh)
            data['access'] = str(refresh.access_token)
    
            # Add extra responses here
            data['username'] = self.user.username
            data['groups'] = self.user.groups.values_list('name', flat=True)
            return data
    
    
    class MyTokenObtainPairView(TokenObtainPairView):
        serializer_class = MyTokenObtainPairSerializer
    
    1. 用自定义视图替换登录视图
    # project/urls.py
    
    from .views import MyTokenObtainPairView
    
    urlpatterns = [
        # path('token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
        path('token/', MyTokenObtainPairView.as_view(), name='token_obtain_pair'),
    ]
    

    ?

    参考资料: SimpleJWT Readme及源码如下:

    【讨论】:

    • 谢谢!当前文档没有提到覆盖验证,您为我节省了大量的故障排除。
    • 文档怎么没有这个答案那么清楚。
    • 在get_token方法中,cls和用户参数的来源或引用在哪里?
    • 为什么这个 validate 不是文档的一部分,这个行不通
    • 我认为您不需要设置刷新和访问,因为它们是在父序列化程序中设置的
    【解决方案2】:

    自定义令牌响应如下:

    from rest_framework_simplejwt.tokens import RefreshToken
        
        
        class LoginView(APIView):
            permission_classes = (AllowAny,)
         
            def post(self, request, *args, **kwargs):
                # ...
        
                # Get user token, include refresh and access token
                token = RefreshToken.for_user(user) 
        
                # Serializer token if it is not correct JSON format ^^
            
                return JsonResponse({'success': 'true', 'token': token, 'user': user})
    

    【讨论】:

      【解决方案3】:

      django-rest-framework-simplejwt README 中的一个非常干净的方法,如下所示

      例如,我的自定义用户模型所在的用户应用程序。关注序列化程序并查看下面的代码示例。

      users/serializers.py:

      from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
      
      
      class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
          @classmethod
          def get_token(cls, user):
              token = super().get_token(user)
      
              # Add custom claims
              token['name'] = user.name
              # Add more custom fields from your custom user model, If you have a
              # custom user model.
              # ...
      
              return token
      

      users/views.py:

      from rest_framework_simplejwt.views import TokenObtainPairView
      
      
      class MyTokenObtainPairView(TokenObtainPairView):
          serializer_class = MyTokenObtainPairSerializer
      

      之后,在您项目的urls.py 中注册上方视图,替换原来的TokenObtainPairView,如下所示。

      from users.views import MyTokenObtainPairView
      
      urlpatterns = [
          ..
          # Simple JWT token urls
          # path('api/token/', TokenObtainPairView.as_view(),
          #      name='token_obtain_pair'),
          path('api/token/', CustomTokenObtainPairView.as_view(),
               name='token_obtain_pair')
          ..
      ]
      

      现在在jwt.io获取访问令牌并对其进行解码

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-11-20
        • 1970-01-01
        • 2020-12-18
        • 2020-02-06
        • 2018-02-18
        • 2020-05-24
        • 2021-04-11
        • 2021-09-09
        相关资源
        最近更新 更多