Added new setting, widget, form and auth backend to allow login via user email address

To enable:
AUTHENTICATION_BACKENDS = ('common.auth.email_auth_backend.EmailAuthBackend',)
COMMON_LOGIN_METHOD = 'email'
This commit is contained in:
Roberto Rosario
2011-08-05 23:36:00 -04:00
parent acd6348dd7
commit 36c7beca84
7 changed files with 92 additions and 5 deletions

View File

View File

@@ -0,0 +1,23 @@
# From: http://www.micahcarrick.com/django-email-authentication.html
from django.contrib.auth.models import User, check_password
from django.contrib.auth.backends import ModelBackend
class EmailAuthBackend(ModelBackend):
"""
Email Authentication Backend
Allows a user to sign in using an email/password pair rather than
a username/password pair.
"""
def authenticate(self, email=None, password=None):
"""
Authenticate a user based on email address as the user name.
"""
try:
user = User.objects.get(email=email)
if user.check_password(password):
return user
except User.DoesNotExist:
return None

View File

@@ -55,3 +55,12 @@ register_setting(
global_name=u'COMMON_AUTO_ADMIN_PASSWORD', global_name=u'COMMON_AUTO_ADMIN_PASSWORD',
default=u'admin', default=u'admin',
) )
register_setting(
namespace=u'common',
module=u'common.conf.settings',
name=u'LOGIN_METHOD',
global_name=u'COMMON_LOGIN_METHOD',
default=u'username',
description=_(u'Controls the mechanism used to authenticated user. Options are: username, email'),
)

View File

@@ -2,9 +2,12 @@ from django import forms
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.db import models from django.db import models
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.contrib.auth.forms import AuthenticationForm
from django.contrib.auth import authenticate
from common.utils import return_attrib from common.utils import return_attrib
from common.widgets import DetailSelectMultiple, PlainWidget, TextAreaDiv from common.widgets import DetailSelectMultiple, PlainWidget, \
TextAreaDiv, EmailInput
class DetailForm(forms.ModelForm): class DetailForm(forms.ModelForm):
@@ -115,3 +118,29 @@ class UserForm(forms.ModelForm):
class Meta: class Meta:
model = User model = User
fields = ('first_name', 'last_name') fields = ('first_name', 'last_name')
class EmailAuthenticationForm(AuthenticationForm):
"""
Override the default authentication form to use email address
authentication
"""
email = forms.CharField(label=_(u'Email'), max_length=75,
widget=EmailInput()
)
def clean(self):
email = self.cleaned_data.get('email')
password = self.cleaned_data.get('password')
if email and password:
self.user_cache = authenticate(email=email, password=password)
if self.user_cache is None:
raise forms.ValidationError(_('Please enter a correct email and password. Note that the password fields is case-sensitive.'))
elif not self.user_cache.is_active:
raise forms.ValidationError(_('This account is inactive.'))
self.check_for_test_cookie()
return self.cleaned_data
# Remove the inherited username field
EmailAuthenticationForm.base_fields.keyOrder = ['email', 'password']

View File

@@ -2,23 +2,22 @@ from django.conf.urls.defaults import patterns, url
from django.views.generic.simple import direct_to_template from django.views.generic.simple import direct_to_template
from django.conf import settings from django.conf import settings
urlpatterns = patterns('common.views', urlpatterns = patterns('common.views',
url(r'^about/$', direct_to_template, {'template': 'about.html'}, 'about'), url(r'^about/$', direct_to_template, {'template': 'about.html'}, 'about'),
#url(r'^password/change/done/$', 'django.contrib.auth.views.password_change_done', {'template_name': 'password_change_done.html'}),
url(r'^password/change/done/$', 'password_change_done', (), name='password_change_done'), url(r'^password/change/done/$', 'password_change_done', (), name='password_change_done'),
url(r'^object/multiple/action/$', 'multi_object_action_view', (), name='multi_object_action_view'), url(r'^object/multiple/action/$', 'multi_object_action_view', (), name='multi_object_action_view'),
url(r'^user/$', 'current_user_details', (), 'current_user_details'), url(r'^user/$', 'current_user_details', (), 'current_user_details'),
url(r'^user/edit/$', 'current_user_edit', (), 'current_user_edit'), url(r'^user/edit/$', 'current_user_edit', (), 'current_user_edit'),
url(r'^login/$', 'login_view', (), name='login_view'),
) )
urlpatterns += patterns('', urlpatterns += patterns('',
url(r'^login/$', 'django.contrib.auth.views.login', {'template_name': 'login.html'}, name='login_view'),
url(r'^logout/$', 'django.contrib.auth.views.logout', {'next_page': '/'}, name='logout_view'), url(r'^logout/$', 'django.contrib.auth.views.logout', {'next_page': '/'}, name='logout_view'),
url(r'^password/change/$', 'django.contrib.auth.views.password_change', {'template_name': 'password_change_form.html', 'post_change_redirect': '/password/change/done/'}, name='password_change_view'), url(r'^password/change/$', 'django.contrib.auth.views.password_change', {'template_name': 'password_change_form.html', 'post_change_redirect': '/password/change/done/'}, name='password_change_view'),
#url(r'^password/change/done/$', 'django.contrib.auth.views.password_change_done', {'template_name': 'password_change_done.html'}),
url(r'^password/reset/$', 'django.contrib.auth.views.password_reset', {'email_template_name': 'password_reset_email.html', 'template_name': 'password_reset_form.html', 'post_reset_redirect': '/password/reset/done'}, name='password_reset_view'), url(r'^password/reset/$', 'django.contrib.auth.views.password_reset', {'email_template_name': 'password_reset_email.html', 'template_name': 'password_reset_form.html', 'post_reset_redirect': '/password/reset/done'}, name='password_reset_view'),
url(r'^password/reset/confirm/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/$', 'django.contrib.auth.views.password_reset_confirm', {'template_name': 'password_reset_confirm.html', 'post_reset_redirect': '/password/reset/complete/'}, name='password_reset_confirm_view'), url(r'^password/reset/confirm/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/$', 'django.contrib.auth.views.password_reset_confirm', {'template_name': 'password_reset_confirm.html', 'post_reset_redirect': '/password/reset/complete/'}, name='password_reset_confirm_view'),
url(r'^password/reset/complete/$', 'django.contrib.auth.views.password_reset_complete', {'template_name': 'password_reset_complete.html'}, name='password_reset_complete_view'), url(r'^password/reset/complete/$', 'django.contrib.auth.views.password_reset_complete', {'template_name': 'password_reset_complete.html'}, name='password_reset_complete_view'),

View File

@@ -7,8 +7,11 @@ from django.contrib import messages
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.utils.http import urlencode from django.utils.http import urlencode
from django.contrib.auth.views import login
from common.forms import ChoiceForm, UserForm, UserForm_view from common.forms import ChoiceForm, UserForm, UserForm_view
from common.forms import EmailAuthenticationForm
from common.conf.settings import LOGIN_METHOD
def password_change_done(request): def password_change_done(request):
@@ -167,3 +170,14 @@ def current_user_edit(request):
'title': _(u'edit current user details'), 'title': _(u'edit current user details'),
}, },
context_instance=RequestContext(request)) context_instance=RequestContext(request))
def login_view(request):
#url(r'^login/$', 'django.contrib.auth.views.login', {'template_name': 'login.html'}, name='login_view'),
#url(r'^login/$', 'django.contrib.auth.views.login', {'template_name': 'login.html', 'authentication_form': EmailAuthenticationForm}, name='login_view'),
kwargs = {'template_name': 'login.html'}
if LOGIN_METHOD == 'email':
kwargs['authentication_form'] = EmailAuthenticationForm
return login(request, **kwargs)

View File

@@ -83,3 +83,16 @@ class TextAreaDiv(forms.widgets.Widget):
conditional_escape(force_unicode(value)))) conditional_escape(force_unicode(value))))
return mark_safe(result.replace('\n', '<br>')) return mark_safe(result.replace('\n', '<br>'))
# From: http://www.peterbe.com/plog/emailinput-html5-django
class EmailInput(forms.widgets.Input):
input_type = 'email'
def render(self, name, value, attrs=None):
if attrs is None:
attrs = {}
attrs.update(dict(autocorrect='off',
autocapitalize='off',
spellcheck='false'))
return super(EmailInput, self).render(name, value, attrs=attrs)