Previously I have been investigating several solutions how to register with email address instead of username. All the sources I found focus on creating a custom backend and rolling the Signup page. While this works for me, I couldn’t find a single solution that explains what to do with the login screen.
First of all my approach with Email authorization
Registration: I take the email address and create a hash of it as the username and store it.
Login: I take the email address again and create a hash of it and try
to find a username with the same hash.
How its done in code:
In the settings:
AUTHENTICATION_BACKENDS = ('MyApp.auth_backends.CustomUserModelBackend',)
CUSTOM_USER_MODEL = 'MyApp.CustomUser'
In models.py
class CustomUser(User):
timezone = models.CharField(max_length=50, default='Europe/London')
objects = UserManager()
I have customized the registration like this:
View.py
def register_page(request):
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
user = CustomUser.objects.create_user(
username=md5(form.cleaned_data['email']).digest().encode('base64')[:-1],
password=form.cleaned_data['password2'],
email=form.cleaned_data['email']
)
return HttpResponseRedirect('/register/success/')
else:
form = RegistrationForm()
variables = RequestContext(request, {'form':form})
return render_to_response('registration/register.html', variables)
in auth_backends.CustomUserModelBackend:
calculate the hash of the given email address to find the related username.
class CustomUserModelBackend(ModelBackend):
def authenticate(self, username=None, password=None):
try:
# The parameter Username is here really just the email address, I get
# the hash for the email parameter and try to find the user.
hash_user = md5(username).digest().encode('base64')[:-1],
user = self.user_class.objects.get(username=hash_user)
if user.check_password(password):
return user
except self.user_class.DoesNotExist:
return None
def get_user(self, user_id):
try:
return self.user_class.objects.get(pk=user_id)
except self.user_class.DoesNotExist:
return None
@property
def user_class(self):
if not hasattr(self, '_user_class'):
self._user_class = get_model(*settings.CUSTOM_USER_MODEL.split('.', 2))
if not self._user_class:
raise ImproperlyConfigured('Could not get custom user model')
return self._user_class
Now I am stuck with login screen.
I have done it like this, but I get redirected back to login screen without getting any error shown.
url.py
(r'^login/$', 'django.contrib.auth.views.login'),
registration/login.html
{% extends "base.html" %}
{% block title %}user login{% endblock %}
{% block head %}User login{% endblock %}
{% block content %}{% if form.errors %}
<p>Your email and password didn't match</p>
{% endif %}
<form action="." method="post">
<p>
<label for="id_username">Email:</label>{{ form.username }}
</p>
<p>
<label for="id_password">Password:</label>{{ form.password }}
</p>
{% csrf_token %}
<input type="hidden" name="next" value="/" />
<input type="submit" value="login" />
</form>
{% endblock %}
I know the solution is already problematic since I need an email input for “username” and not a charfield.
1) What do I have to do to override the field type?
2) I still can’t login, it says username doesn’t match password.
I debugged it in Authenticate and it doesnt find the user
hash_user = md5(username).digest().encode('base64')[:-1],
user = self.user_class.objects.get(username=hash_user)
Isn’t the hash of the same email address always the same? What could I be missing?
Update:
I can see clearly the hash code is saved as username in the database and I can see how within the Authenticate user = self.user_class.objects.get(username=hash_user) the hashcode is the same value as in the database. However it still doesn’t retrieve the user. Why?


UPDATE 2:
I found the problem. I had one comma there by mistake and that turned the hash into a tuple. Oh dear
This is correct and works:
hash_user = md5(username).digest().encode('base64')[:-1]
user = self.user_class.objects.get(username=hash_user)
We have now the full solution here. Just one thing.
Is anyone able to help me with 1) ? How can I override the username charfield please?
Sadly, this is not currently possible.