简体   繁体   English

将自定义用户身份验证添加到 django-rest-framework-simple-jwt

[英]Adding custom user authentication to django-rest-framework-simple-jwt

I want to add user login via One-time Password as well as the usual username/password method in django.我想通过一次性密码以及 django 中常用的用户名/密码方法添加用户登录。 In order to do so, either username/password or username/OTP are sent from client to sever and based on the provided pair of fields, I need to return access and refresh token if the user is authenticated.为此,用户名/密码或用户名/OTP 从客户端发送到服务器,并且基于提供的字段对,如果用户通过身份验证,我需要返回访问和刷新令牌。 I am using django's simple-jwt.我正在使用 django 的 simple-jwt。 I know that I have to override TokenObtainPairView and TokenObtainSerializer.我知道我必须重写 TokenObtainPairView 和 TokenObtainSerializer。 The problem is, I want to do the field validation part myself.问题是,我想自己做字段验证部分。

In my views, I override simple-jwt's default view.在我看来,我覆盖了 simple-jwt 的默认视图。

#views.py

class MyTokenObtainPairView(TokenObtainPairView):
    serializer_class = MyTokenObtainPairSerializer

And I override the serializer like below:我重写了如下的序列化程序:

#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

So, if client passes user credentials in one of the possible forms below, I will be able to authenticate it and return token pair.因此,如果客户端在下面可能的 forms 之一中传递用户凭据,我将能够对其进行身份验证并返回令牌对。

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

or或者

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

The problem is, when I send data in the second form, I get 400 BadRequest:password is required .问题是,当我以第二种形式发送数据时,我得到400 BadRequest:password is required How can I customize fields and their validation?如何自定义字段及其验证?

As Saiful Azad mentioned in comments, one possible method is to use separate serializers for each scenario.正如Saiful Azad在评论中提到的,一种可能的方法是为每个场景使用单独的序列化程序。

#views.py

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

Then, you can implement your own serializer for otp verification.然后,您可以实现自己的序列化程序进行 otp 验证。 I used simple-jwt's implementation to implement my own serializer and use my custom authentication method.我使用simple-jwt 的实现来实现我自己的序列化程序并使用我的自定义身份验证方法。

In your urls.py在你的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")
]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM