在 django-rest-framework-simple-jwt 中使用三个字段进行身份验证
Authentication with three fields in django-rest-framework-simple-jwt
我正在 DRF 中进行自定义身份验证。用户应发送 3 个字段(phone、电子邮件、密码)。
我在关注这个答案
(我覆盖了 TokenObtainPairSerializer
和 TokenObtainPairView
)
问题:对于下面的请求,我收到了一个空响应{}
,但预期是令牌或错误消息
{
"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
我正在 DRF 中进行自定义身份验证。用户应发送 3 个字段(phone、电子邮件、密码)。
我在关注这个答案TokenObtainPairSerializer
和 TokenObtainPairView
)
问题:对于下面的请求,我收到了一个空响应{}
,但预期是令牌或错误消息
{
"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