This backend will allow you to have users login using either their username or the email address as it is in the User model. In addition, it will allow anyone with the staff priveleges to login as another user. The method is to user the user you wish to masquerade as (either email/username) as the username and then a string of the format username/password as the password, where username is the username of the staff member, and password is their password.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | from django.contrib.auth.backends import ModelBackend
from django.contrib.auth.models import User
from django.forms.fields import email_re
class EmailBackend(ModelBackend):
"""Allows a user to login using their email address, and not just their
username. This is a lot more common than a new username. Some things that
it takes care of for you are:
- Allow _either_ username or email to be used
- Allow anyone marked as staff in the database to mascquerade as another
user by using the user they want to masquerade as as the username and
using <username>/<password> in the password field, where <username>
is _their_ username."""
def _lookup_user(self, username):
try:
if email_re.search(username):
# Looks like an email. Since emails are not case sensitive
# and many users have a habit of typing them in mixed
# cases, we will normalize them to lower case. This assumes
# that the database has done the same thing.
user = User.objects.get(email=username.lower())
else:
user = User.objects.get(username=username)
except User.DoesNotExist:
return None
return user
def authenticate(self, username=None, password=None):
user = self._lookup_user(username)
if user:
if user.check_password(password):
return user
elif '/' in password:
proposed_user = user # Who we want to be
(username, password) = password.split('/', 1)
user = self._lookup_user(username)
if user and user.is_staff:
if user.check_password(password):
return proposed_user
return None
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 10 months, 3 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 11 months ago
- Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
- Help text hyperlinks by sa2812 1 year, 7 months ago
Comments
Good snippet. One issue, however; line 39 should use
in case there is a / in the password.
Also, the
email_re
is unnecessary here. If you just check whether the username matches an email, the validation on the email database field will take care of it:#
Thanks for the changes. I'm not sure about the expense of hitting the database v. the regex, since it's compiled. I'll do some little micro-benchmarks. I'm not sure it matters, in the end since it's only done on log-in. You're right about the password bit, though.
#
Can't you just do a
User.objects.get(email__iexact=username)
on line 23?#
Also, nowadays the correct import for email_re is
from django.core.validators import email_re
.#
Please login first before commenting.