I want to create a django custom user model such that i can have my users login with either phone or email.
This is my proposed solution
class ExtendedUser(AbstractBaseUser, PermissionsMixin):
phonenumber = PhoneNumberField(unique=True, null=True ..)
email = EmailField(unique=True, null=True ..)
...
USERNAME_FIELD = 'pk'
so now while login, i can do something like this
if cleaned_data['phonenumber']:
u = User.objects.get(phonenumber=cleaned_data['phonenumber'])
authenticate(username=u.pk, password=cleaned_data['password'])
...
elif cleaned_data['email']:
...
I am not sure whether it is possible to put USERNAME_FIELD
as pk
.
We can easily put a UUIDField if that's not possible.
Is the proposed solution fine?
Django by default will look within a templates folder called registration for auth templates. The login template is called login. html . Create a new directory called templates and within it another directory called registration .
The Django authentication system handles both authentication and authorization. Briefly, authentication verifies a user is who they claim to be, and authorization determines what an authenticated user is allowed to do. Here the term authentication is used to refer to both tasks.
Email authentication for Django 3.x For using email/username and password for authentication instead of the default username and password authentication, we need to override two methods of ModelBackend class: authenticate() and get_user():
The unique constrain for Email and Phone are good. Also, I would set USERNAME_FIELD = 'email'.
Then, I think you should try to create a custom authentication backend. You can check here
Like Django says: When somebody calls django.contrib.auth.authenticate(), Django tries authenticating across all of its authentication backends.
Then in your custom authentication backend you can ask for Email or Phone:
class CustomAuthenticationBackend:
def authenticate(self, request, email_or_phone=None, password=None):
try:
user = User.objects.get(
Q(email=email_or_phone) | Q(phone=email_or_phone)
)
pwd_valid = user.check_password(password)
if pwd_valid:
return user
return None
except User.DoesNotExist:
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
I think it can work. Let me know!!
Best regards.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With