I have 2 views in my task 1. accepts phone number and password authentication to login user
2 . accepts phone number and token without password ,to perform that i created custom backend in which authentication done without password
when I added this custom backend in AUTHENTICTION BACKENDS in settings it make view 2 login without password auth, user login using any password! so how to add 2 backends in settings without conflicting each other
custom backend
class PasswordlessAuthBackend(ModelBackend):
"""Log in to Django without providing a password."""
# model=UserProfile
def authenticate(self,auth_token=None, password=None,username=None,phone_number=None,):
try:
return UserProfile.objects.get(phone_number=phone_number)
except UserProfile.DoesNotExist:
return None
def get_user(self, user_id):
try:
return UserProfile.objects.get(pk=user_id)
except UserProfile.DoesNotExist:
return None
views.py:
class LoginView(APIView):
serializer_class = LoginSerializer
authentication_classes = (ModelBackend,)
def post(self, request, *args, **kwargs):
serializer = self.serializer_class(data=request.data
)
if serializer.is_valid(raise_exception=True):
new_data = serializer.data
user = serializer.validated_data
login(request,user,backend="django.contrib.auth.backends.ModelBackend")
token, created = Token.objects.get_or_create(user=user)
return Response(
{'user':new_data,'token':token.key,},
status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class TokenView(APIView):
throttle_classes=()
permission_classes = ()
# authentication_classes = (PasswordlessAuthBackend,)
serializer_class=TokenSerializer
def post(self, request, *args, **kwargs):
serializer = self.serializer_class(data=request.data,
context={'request': request})
if serializer.is_valid(raise_exception=True):
user = serializer.validated_data
user.backend='accounts.auth_backends.PasswordlessAuthBackend'
print(user)
token, created = Token.objects.get_or_create(user=user)
login(request,user,backend='accounts.auth_backends.PasswordlessAuthBackend')
return Response({
'token': token.key,
'user_id': user.pk,},
serializers.py
class UserProfileSerializer(serializers.ModelSerializer):
email=serializers.EmailField(required=False)
class Meta:
model = UserProfile
fields = ('first_name','last_name','country_code','phone_number','gender','birthdate','avatar','email')
def create(self, validated_data):
user = UserProfile.objects.create(**validated_data)
return user
class LoginSerializer(serializers.Serializer):
phone_number = serializers.CharField(required=True, allow_blank=False)
password = serializers.CharField(required=True,style={'input_type': 'password'})
def validate(self, attrs, ):
user = authenticate(
phone_number=attrs['phone_number'], password=attrs['password'])
# user = self._validate_phonenumber(phonenumber, first_token)
if user is None:
raise serializers.ValidationError('invalid credentials provided')
return user
class TokenSerializer(serializers.Serializer):
phone_number = serializers.CharField(required=True, allow_blank=False)
def validate(self, attrs,):
user = authenticate(
phone_number=attrs['phone_number'])
if user is None:
raise serializers.ValidationError('invalid credentials provided')
self.instance = user
return user
settings.py:
AUTHENTICATION_BACKENDS = (
'accounts.auth_backends.PasswordlessAuthBackend',
"django.contrib.auth.backends.ModelBackend",
)
It appears that your PasswordlessAuthBackend
logs the user in without checking the password/token.
Django inspects the parameter names for your backend to determine if it can be called. Try making a single backend for each use-case, with only the parameters required for that auth (e.g. phone_number, token)
class CustomAuthBackend:
def authenticate(phone_number=None, token=None):
try:
phone = normalize_phone(phone) # standardize to single format
return User.objects.get(phone=phone, token=token) # or whatever
except ObjectDoesNotExist:
return None
The serializer and view can be combined in any way, but really just call authenticate. You seem to be doing this already.
login
is only needed if you are doing session authauthenticate()
will set user.backend
for you, which login()
will read. You don't need to set it manually in the call.