将自定义用户身份验证添加到 django-rest-framework-simple-jwt
Adding custom user authentication to django-rest-framework-simple-jwt
我想通过一次性密码以及 django 中常用的 username/password 方法添加用户登录。为此,username/password 或 username/OTP 从客户端发送到服务器,并且根据提供的字段对,如果用户通过身份验证,我需要 return 访问和刷新令牌.我正在使用 django 的 simple-jwt。我知道我必须重写 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
因此,如果客户端以以下可能的形式之一传递用户凭据,我将能够对其进行身份验证和 return 令牌对。
{
"username" : "Winston",
"password" : "testpass"
}
或
{
"username" : "Winston",
"otp" : "testotp"
}
问题是,当我以第二种形式发送数据时,我得到 400 BadRequest:password is required
。如何自定义字段及其验证?
如评论中Saiful Azad所述,一种可能的方法是为每个场景使用单独的序列化器。
#views.py
class MyTokenObtainPairView(TokenObtainPairView):
def get_serializer_class(self):
if ("otp" in self.request.data):
return MyTokenObtainPairSerializer
return TokenObtainPairSerializer
然后,您可以实现自己的序列化程序来进行otp 验证。我使用 simple-jwt's implementation 来实现我自己的序列化程序并使用我的自定义身份验证方法。
在你的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")
]
我想通过一次性密码以及 django 中常用的 username/password 方法添加用户登录。为此,username/password 或 username/OTP 从客户端发送到服务器,并且根据提供的字段对,如果用户通过身份验证,我需要 return 访问和刷新令牌.我正在使用 django 的 simple-jwt。我知道我必须重写 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
因此,如果客户端以以下可能的形式之一传递用户凭据,我将能够对其进行身份验证和 return 令牌对。
{
"username" : "Winston",
"password" : "testpass"
}
或
{
"username" : "Winston",
"otp" : "testotp"
}
问题是,当我以第二种形式发送数据时,我得到 400 BadRequest:password is required
。如何自定义字段及其验证?
如评论中Saiful Azad所述,一种可能的方法是为每个场景使用单独的序列化器。
#views.py
class MyTokenObtainPairView(TokenObtainPairView):
def get_serializer_class(self):
if ("otp" in self.request.data):
return MyTokenObtainPairSerializer
return TokenObtainPairSerializer
然后,您可以实现自己的序列化程序来进行otp 验证。我使用 simple-jwt's implementation 来实现我自己的序列化程序并使用我的自定义身份验证方法。
在你的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")
]