Аутентификация с тремя полями в django-rest-framework-simple-jwt
Я работаю над пользовательской аутентификацией в DRF. Пользователь должен отправить 3 поля ( телефон, email, пароль).
Я следовал этому ответу Добавление пользовательской аутентификации в django-rest-framework-simple-jwt.
(Я переопределял TokenObtainPairSerializer
и TokenObtainPairView
)
Я использовал этот исходный код 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
class LoginUserSerializer(serializers.Serializer):
email = serializers.EmailField()
phone_number = serializers.CharField()
password = serializers.CharField(write_only=True)
views.py
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
)