版權所有,轉載請註明出處:http://guangboo.org/2013/03/27/authentication-using-email-in-django
django自帶的驗證功能免去了我們的大量工作,它提供了驗證、授權相關的接口,我們只有非常少的代碼就可以實現,但是django自帶的身份驗證的方法只能使用用戶名來進行驗證,如果要想使用email進行驗證的話,就需要自己編寫一些代碼了。
爲使得我們能在使用django提供的驗證功能時,能夠使用email進行身份驗證,本文提出一個簡單的解決方案,使盡量少的編寫代碼,同時又能實現上面的功能。本文使用環境django(1.4.2)+python(2.7.3)。
django的身份驗證授權等功能在模塊django.contrib.auth模塊下,該模塊下提供了默認的驗證表單,修改密碼,找回密碼等表單,驗證,登錄接口等。其中views.py下提供了login和logout方法,用戶登錄和註銷,當然還包含其他的如登錄跳轉,重置密碼,修改密碼等。這些view方法都有很多的參數,都是爲了擴展而添加的,這些方法我們可以直接拿來使用,如果我們不考慮email驗證或登錄界面的話,就可以使用如下代碼:
from django.conf.urls import patterns, include, url
urlpatterns = patterns('',
url(r'^login/$', 'django.contrib.auth.views.login', name = 'login'),
)
只要將上面的三行代碼拷貝到urls.py文件中,就可以實現login的功能,只是登錄界面是admin的登錄界面,並且使用默認的用戶名和密碼進行驗證。如果我們查看django.contrib.auth.views.login方法的源代碼的話,就會發現login的方法簽名爲:
def login(request, template_name='registration/login.html',
redirect_field_name=REDIRECT_FIELD_NAME,
authentication_form=AuthenticationForm,
current_app=None, extra_context=None)
login方法有很多參數,並且都是有默認值的,對我們來說,最常用的就是template_name參數了,我們可以這樣修改urls.py文件,實現登錄界面的自定義。
urlpatterns = patterns('',
url(r'^login/$', 'django.contrib.auth.views.login', {'template_name':'account/long.html'}, name =
'login'),
)
與前面的代碼比較,在url方法中添加了一個參數 {'template_name':'account/long.html'},該參數就會傳遞給login方法,從而就實現修改登錄界面的目的了。也許你會疑惑,爲什麼login方法中爲什麼沒有身份驗證的代碼,其實身份驗證的功能是實現在form中的,就是默認的身份驗證表單AuthenticationForm,我們繼續閱讀AuthenticationForm表單的源代碼:django.contrib.auth.forms.AuthenticationForm,我們會發現身份驗證功能的實現,是在方法clean中,代碼如下:
def clean(self):
username = self.cleaned_data.get('username')
password = self.cleaned_data.get('password')
if username and password:
self.user_cache = authenticate(username=username,
password=password)
if self.user_cache is None:
raise forms.ValidationError(
self.error_messages['invalid_login'])
elif not self.user_cache.is_active:
raise forms.ValidationError(self.error_messages['inactive'])
self.check_for_test_cookie()
return self.cleaned_data
其中authenticate方法就是我們要找的驗證代碼,當然到此我們已經找到驗證的實現,我們就可以重寫一個驗證表單,重新實現clean方法就可以實現我們自己的驗證方式--使用email驗證,然後在
{'template_name':'account/long.html'}參數中添加自定義的驗證表單類,如:
urlpatterns = patterns('',
url(r'^login/$', 'django.contrib.auth.views.login',
{'template_name':'account/long.html','authentication_form':CustomAuthForm}, name = 'login'),
)
其中CustomAuthForm是我們自定義的驗證表單,我們可以參考django自動的AuthenticationForm的實現編寫我們自己的CustomAuthForm類,這裏就不在給出實例,這是一種方法。
另一種方法,我們定義一個backend類,如下:
# -*- coding:utf-8 -*-
# backends.py
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth.models import User
class EmailCheckModelBackend(ModelBackend):
def authenticate(self, username = None, password = None, is_staff = None):
try:
user = User.objects.get(email = username)
if user.check_password(password):
if is_staff is not None:
if user.is_staff == is_staff:
return user
else:
return None
return user
except User.DoesNotExist:
return None
並且在settings.py文件中添加如下代碼即可:
AUTHENTICATION_BACKENDS = ('account.backends.EmailCheckModelBackend',)
需要說明的是,authenticate方法簽名中的原有參數名稱最後不要修改,因爲admin的驗證方式也會使用該backed,如果你仔細觀察AuthenticationForm的clean方法的話,authenticate方法調用是傳遞了參數名的,如果我們將username參數名該成了email或者其他名稱的話,admin就無法登陸了。