Django: Changing/Allowing User's login username to also use his/her e-mail
-
28-09-2019 - |
Question
As my title says, I want to know if I there's a way to allow a user to use not only his username, but also his user's email to login. I want to standardize the login procedure because at the moment I'm having my users use many different conventions and it gets pretty messy.
Solution
You could probably do this if you enforce unique email addresses. Meaning no user can have the same e-mail address. This way you could fetch the user by e-mail address and log them in.
The form might look something like this:
<form method="post" action="{% url myproject.views.login %}">
<p>Username</p>
<input type='text' name='username'/>
<p>Password</p>
<input type='password' name='password'/>
<input type="submit" value="Login"/>
</form>
The view method might look something like this:
def login( request ):
username = request.POST['username']
password = request.POST['password']
user = User.objects.filter( email = username )[0]
if( user is not None ):
# -- the user was retrieved by an email address
# -- now you can authenticate and log them in log them in
from django.contrib import auth
user = auth.authenticate( user.username, password )
if( user is not None ):
auth.login( user, request )
OpenID might be another way to go: http://bit.ly/a2OlHX
Ensure unique e-mail addresses per user: http://bit.ly/aOaAbw
OTHER TIPS
I think I 'solved' my problem, at least it's functional, for now. I decided to use my own authentication backend. I created a file 'auth_backends.py' and added it to AUTHENTICATION_BACKENDS in my settings.py:
My login form fields only contain 'username' and password. The only way I'm doing to check if the entered username is in fact his username or email, is by doing the .find('@'). Is there a better way to check for it? Would this be enough? The whole reason I'm doing this is because it's easier for the user to remember his/her email than his username (which is actually an 'id' consisting of numbers).
I'm also going to have to take care of duplicate emails.
from django.conf import settings
from django.contrib.auth.backends import ModelBackend
from django.core.exceptions import ImproperlyConfigured
from django.db.models import get_model
from django.contrib.auth.models import User
class CustomUserModelBackend(ModelBackend):
def authenticate(self, **credentials):
if 'username' in credentials:
if credentials['username'].find('@') > 0:
return self.authenticate_by_email(**credentials)
else:
return self.authenticate_by_username(**credentials)
def authenticate_by_username(self, username=None, password=None):
try:
user = User.objects.get(username=username)
if user.check_password(password):
return user
except User.DoesNotExist:
return None
def authenticate_by_email(self, username=None, password=None):
try:
user = User.objects.get(email=username)
if user.check_password(password):
return user
except User.DoesNotExist:
return None