Добавление пользовательской аутентификации пользователя в django-rest-framework-simple-jwt

Я хочу добавить логин пользователя через одноразовый пароль, а также обычный метод имени пользователя / пароля в django. Для этого либо имя пользователя / пароль, либо имя пользователя / OTP отправляются от клиента к серверу, и на основе предоставленной пары полей мне нужно вернуть доступ и обновить токен, если пользователь аутентифицирован. Я использую простой-jwt django. Я знаю, что мне нужно переопределить TokenObtainPairView и TokenObtainSerializer. Проблема в том, что я хочу выполнить часть проверки поля самостоятельно.

В своих представлениях я переопределяю представление по умолчанию для simple-jwt.

#views.py

class MyTokenObtainPairView(TokenObtainPairView):
    serializer_class = MyTokenObtainPairSerializer

И я переопределяю сериализатор, как показано ниже:

#serializers.py

class MyTokenObtainPairSerializer(TokenObtainPairSerializer):

    def validate(self, attrs):
        try:
            request = self.context["request"]
        except KeyError:
            pass

        try:
            request_data = json.loads(request.body)
            if("username" in request_data and "password" in request_data):
                # default scenario in simple-jwt  
                pass
            elif("username" in request_data and "otp" in request_data):                                   
                # validate username/otp manually and return access/token pair if successful
                pass

            else:
                # some fields were missing
                raise serializers.ValidationError({"username/otp or username/password" : "These fields are required"})

        except:
            pass

Итак, если клиент передает учетные данные пользователя в одной из возможных форм ниже, я смогу аутентифицировать его и вернуть пару токенов.

{
   "username" : "Winston",
   "password" : "testpass"
}

or

{
    "username" : "Winston",
    "otp" : "testotp"
}

Проблема в том, что когда я отправляю данные во второй форме, я получаю 400 BadRequest:password is required. Как я могу настроить поля и их проверку?


comment
В чем причина использования одного сериализатора? Альтернативный способ написать 2 отдельных сериализатора для пароля и OTP.   -  person Saiful Azad    schedule 18.04.2020


Ответы (2)


Как упоминал Сайфул Азад в комментариях, одним из возможных методов является использование отдельных сериализаторов для каждого сценария.

#views.py

class MyTokenObtainPairView(TokenObtainPairView):
    def get_serializer_class(self):
        if ("otp" in self.request.data):
            return MyTokenObtainPairSerializer
        return TokenObtainPairSerializer

Затем вы можете реализовать свой собственный сериализатор для проверки OTP. Я использовал реализацию simple-jwt реализовать собственный сериализатор и использовать собственный метод аутентификации.

person Winston    schedule 19.04.2020

В вашем urls.py

# Imports
from rest_framework_simplejwt.tokens import RefreshToken
from django.contrib.auth.models import User
from rest_framework.response import Response
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import AllowAny

@api_view(['GET'])
@permission_classes([AllowAny])
def get_tokens_for_user(request):

    # find the user base in params
    user = User.objects.first()

    refresh = RefreshToken.for_user(user)

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

urlpatterns = [
    path('login', get_tokens_for_user, name="login")
]
person Peter Maquiran    schedule 05.02.2021