在 django-rest-framework-simple-jwt 中使用三个字段进行身份验证

Authentication with three fields in django-rest-framework-simple-jwt

我正在 DRF 中进行自定义身份验证。用户应发送 3 个字段(phone、电子邮件、密码)。

我在关注这个答案 (我覆盖了 TokenObtainPairSerializerTokenObtainPairView

我正在使用这个源代码https://github.com/jazzband/djangorestframework-simplejwt/blob/master/rest_framework_simplejwt/serializers.py

问题:对于下面的请求,我收到了一个空响应{},但预期是令牌或错误消息

{
    "email": "admin1@admin2.ru",
    "password": "admin123456",
    "phone_number": "123132"
}

我的代码:views.py

class CustomTokenObtainPairView(TokenObtainPairView):
    serializer_class = CustomTokenObtainPairSerializer

serializers.py

class CustomTokenObtainPairSerializer(TokenObtainPairSerializer):
    username_field = CustomUser.USERNAME_FIELD

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.fields[self.username_field] = serializers.CharField()
        self.fields['password'] = PasswordField()
        self.fields['phone_number'] = serializers.CharField() # authentication requires 3 fields

    def validate(self, attrs):
        authenticate_kwargs = {
            self.username_field: attrs[self.username_field],
            'password': attrs['password'],
            'phone_number': attrs['phone_number']
        }
        try:
            authenticate_kwargs["request"] = self.context["request"]
        except KeyError:
            pass

        self.user = authenticate(**authenticate_kwargs)

        if not api_settings.USER_AUTHENTICATION_RULE(self.user):
            raise exceptions.AuthenticationFailed(
                self.error_messages["no_active_account"],
                "no_active_account",
            )

        return {}

使用此代码

 class MyTokenObtainPairSerializer(TokenObtainPairSerializer):

     def validate(self, attrs):
         data = super().validate(attrs)
         data['username'] = self.user.email
         data['email'] = self.user.email
         serializer = serializers.UserSerializerWithToken(self.user).data
         for k, v in serializer.items():
             data[k] = v
         return data


 ## login view
 class MyTokenObtainPairView(TokenObtainPairView):
     serializer_class = MyTokenObtainPairSerializer

序列化器文件

 class UserSerializer(serializers.ModelSerializer):
     isStaffAdmin = serializers.SerializerMethodField(read_only=True)

     class Meta:
         model = CustomerTable
         fields = ['id', 'username', 'email', 'isStaffAdmin']


     def get_isStaffAdmin(self, obj):
         return obj.is_staff




 class UserSerializerWithToken(UserSerializer):

     token = serializers.SerializerMethodField(read_only=True)

     class Meta:
         model = CustomerTable
         fields = ['id', 'username', 'email', 'isStaffAdmin', 'token']

     def get_token(self, obj):
         token = RefreshToken.for_user(obj)
         return str(token.access_token)

     def get_isStaffAdmin(self, obj):
         if obj.is_staff and obj.is_active:
             return 2
         else:
             error = {'message': "Invalid User"}
             raise serializers.ValidationError(error)

您可以根据需要自定义此代码。

让我们尝试手动登录并生成令牌:

serializers.py

from rest_framework import serializer


class LoginUserSerializer(serializers.Serializer):
    email = serializers.EmailField()
    phone_number = serializers.CharField()
    password = serializers.CharField(write_only=True)

views.py

from django.contrib.auth import authenticate

from rest_framework import status, serializers
from rest_framework.response import Response
from rest_framework.views import APIView

from rest_framework_simplejwt.tokens import RefreshToken


class LoginUserApi(APIView):

    def post(self, request):
        serializer = LoginUserSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        data = serializer.validated_data # Fetch the data form serializer

        user = authenticate(email=data['email'], password=data['password']) # check for email and password
        if not user or user.phone_number != data['phone_number']: # check for phone
            raise serializers.ValidationError({'detail':'Incorrect email, phone, or password'})

        # Generate Token
        refresh = RefreshToken.for_user(user)

        return Response(
            {
                'access': str(refresh.access_token),
                'refresh': str(refresh)
            }
            , status=status.HTTP_200_OK
            )

如何从 Simple JWT 手动创建令牌 docs