使用Django認(rèn)證(authentication)框架
Django擁有一個內(nèi)置的認(rèn)證(authentication)框架用來操作用戶認(rèn)證(authentication)聊浅,會話(sessions)饼灿,權(quán)限(permissions)以及用戶組涉馅。
這個認(rèn)證(authentication)系統(tǒng)包含了一些普通用戶操作視圖(views)湃鹊,例如:登錄瘸恼,登出,修改密碼以及重置密碼讲逛。
這個認(rèn)證(authentication)系統(tǒng)還包含了以下模型(models):
User:一個包含了基礎(chǔ)字段的用戶模型(model)匣摘;這個模型(model)的主要字段有:username店诗, password, email, first_name, last_name, is_active。
Group:一個組模型(model)用來分類用戶
Permission:執(zhí)行特定操作的標(biāo)識
這個框架還包含默認(rèn)的認(rèn)證(authentication)視圖(views)和表單(forms)音榜,我們之后會用到庞瘸。
注:請注意authentication和login中的不同點:authenticate()檢查用戶認(rèn)證信息,如果用戶是正確的則返回一個用戶對象赠叼;login()將用戶設(shè)置到當(dāng)前的會話(session)中擦囊。
使用Django認(rèn)證(authentication)視圖(views)
Django在認(rèn)證(authentication)框架中包含了一些開箱即用的:表單(forms)和視圖(views)。
你之前創(chuàng)建的登錄視圖(view)是一個非常好的練習(xí)用來理解Django中的用戶認(rèn)證(authentication)過程梅割。無論如何霜第,你可以在大部分的案例中使用默認(rèn)的Django認(rèn)證(authentication)視圖(views)葛家。
Django提供以下視圖(views)來處理認(rèn)證(authentication):
login:操作表單(form)中的登錄然后登錄一個用戶
logout:登出一個用戶
logout_then_login:登出一個用戶然后重定向這個用戶到登錄頁面
Django提供以下視圖(views)來操作密碼修改:
password_change:操作一個表單(form)來修改用戶密碼
password_change_done:當(dāng)用戶成功修改他的密碼后提供一個成功提示頁面
Django還包含了以下視圖(views)允許用戶重置他們的密碼:
password_reset:允許用戶重置他的密碼户辞。它會生成一條帶有一個token的一次性使用鏈接然后發(fā)送到用戶的郵箱中。
password_reset_done:告知用戶已經(jīng)發(fā)送了一封可以用來重置密碼的郵件到他的郵箱中癞谒。
password_reset_complete:當(dāng)用戶重置完成他的密碼后提供一個成功提示頁面底燎。
? ? ? ? 在你的account應(yīng)用中的template目錄下創(chuàng)建一個新的目錄命名為registration。這個路徑是Django認(rèn)證(authentication)視圖(view)期望你的認(rèn)證(authentication)模塊(template)默認(rèn)的存放路徑弹砚。
用戶登錄
<div>
????????<form action={% url "login" %} method="post">
????????????????{{ form.as_p }}
? ? ? ? ? ? ? ? {% csrf_token %}
? ? ? ? ? ? ? ? <input type="hidden" name="next" value="{{ next }}"/>
? ? ? ? ? ? ? ? <p><input type="submit" value="登錄"></p>
????????</form>
</div>
Django默認(rèn)使用位于django.contrib.auth.forms中的AuthenticationForm双仍。這個表單(form)會嘗試對用戶進行認(rèn)證,如果登錄不成功就會拋出一個驗證錯誤桌吃。如果提供了錯誤的認(rèn)證信息朱沃,我們可以在模板(template)中使用{% if form.errors %}來找到錯誤。
注意:
? ? ? (1).我們添加了一個隱藏的HTML元素來提交叫做next的變量值。當(dāng)你在請求(request)中傳遞一個next參數(shù)(舉個例子:http://127.0.0.1:8000/account/login/?next=/account/)逗物,這個變量是登錄視圖(view)首個設(shè)置的參數(shù)搬卒。next參數(shù)必須是一個URL。當(dāng)這個參數(shù)被給予的時候翎卓,Django登錄視圖(view)將會在用戶登錄完成后重定向到給予的URL契邀。
? ? (2).在我們的地址配置中所包含的logtou_then_login視圖(view)不需要任何模板(template),因為它執(zhí)行了一個重定向到登錄視圖(view)失暴。
????(3).login_required裝飾器(decorator)會檢查當(dāng)前用戶是否通過認(rèn)證坯门,如果用戶沒有通過認(rèn)證,它會把用戶重定向到帶有一個名為next的GET參數(shù)的登錄URL逗扒,該GET參數(shù)保存的變量為用戶當(dāng)前嘗試訪問的頁面URL古戴。
from django.core.urlresolvers import reverse_lazy
LOGIN_REDIRECT_URL = reverse_lazy('dashboard')
LOGIN_URL = reverse_lazy('login')
LOGOUT_URL = reverse_lazy('logout')
這些設(shè)置的意義:
LOGIN_REDIRECT_URL:告訴Django用戶登錄成功后如果contrib.auth.views.login視圖(view)沒有獲取到next參數(shù)將會默認(rèn)重定向到哪個URL。
LOGIN_URL:重定向用戶登錄的URL(例如:使用login_required裝飾器(decorator))缴阎。
LOGOUT_URL:重定向用戶登出的URL允瞧。
????????我們使用reverse_lazy()來通過它們的名字動態(tài)構(gòu)建URL。reverse_lazy()方法就像reverse()所做的一樣reverses URLs蛮拔,但是你可以通過使用這種方式在你項目的URL配置被讀取之前進行reverse URLs述暂。
????????通過認(rèn)證(authentication)中間件當(dāng)前的用戶被設(shè)置在HTTP請求(request)對象中。你可以通過使用request.user訪問用戶信息建炫。你會發(fā)現(xiàn)一個用戶對象在請求(request)中畦韭,即便這個用戶并沒有認(rèn)證通過。一個未認(rèn)證的用戶在請求(request)中被設(shè)置成一個AnonymousUser的實例肛跌。一個最好的方法來檢查當(dāng)前的用戶是否通過認(rèn)證是通過調(diào)用request.user.is_authenticated()艺配。
如果在你的登出頁面中看到了Django管理站點的登出頁面,檢查項目settings.py中的INSTALLED_APPS,確保django.contrib.admin在account應(yīng)用的后面
修改密碼視圖(views)
password_change視圖(view)將會操作表單(form)進行修改密碼衍慎,當(dāng)用戶成功的修改他的密碼后password_change_done將會顯示一條成功信息转唉。
password_reset_email.html(渲染發(fā)送給用戶的重置密碼郵件)
Someone asked for password reset for email {{ email }}. Follow the link below:
{{ protocol }}://{{ domain }}{% url "password_reset_confirm" uidb64=uid token=token %}
Your username, in case you've forgotten: {{ user.get_username }}
再創(chuàng)建另一個模板(template)password_reset_confirm.html,為它添加如下代碼:
{% block content %}
????????Reset your password
????????????{% if validlink %}
????????????????????????Please enter your new password twice:
????????????????????????{{ form.as_p }}
????????????????????????{% csrf_token %}
????????????????????????<input type="submit" value="修改密碼">
????????????{% else %}
????????????????????The password reset link was invalid, possibly because it has already been used. Please request a new password reset.
????????????{% endif %}
{% endblock %}
在以上模板中稳捆,我們將會檢查重置鏈接是否有效赠法。Django重置密碼視圖(view)會設(shè)置這個變量然后將它帶入這個模板(template)的上下文環(huán)境中。如果重置鏈接有效乔夯,我們展示用戶密碼重置表單(form)砖织。
用戶注冊
Django還提供一個UserCreationForm表單(form)給你使用,它位于django.contrib.auth.forms非常類似與我們剛才創(chuàng)建的表單(form)末荐。
編輯他們的pfofile:
? ??????user_form = UserEditForm(instance=request.user,data=request.POST)
使用一個定制User模型(model)
????????Django還提供一個方法可以使用你自己定制的模型(model)來替代整個User模型(model)侧纯。你自己的用戶類需要繼承Django的AbstractUser類,這個類提供了一個抽象的模型(model)用來完整執(zhí)行默認(rèn)用戶
使用messages框架
當(dāng)處理用戶的操作時甲脏,你可能想要通知你的用戶關(guān)于他們操作的結(jié)果眶熬。Django有一個內(nèi)置的messages框架允許你給你的用戶顯示一次性的提示妹笆。
messages框架提供了一個簡單的方法添加消息給用戶。消息被存儲在數(shù)據(jù)庫中并且會在用戶的下一次請求中展示娜氏。你可以在你的視圖(views)中導(dǎo)入messages模塊來使用消息messages框架晾浴,用簡單的快捷方式添加新的messages
from django.contrib import messages
messages.error(request, 'Something went wrong')
你可以使用add_message()方法創(chuàng)建新的messages或用以下任意一個快捷方法:
success():當(dāng)操作成功后顯示成功的messages
info():展示messages
warning():某些還沒有達到失敗的程度但已經(jīng)包含有失敗的風(fēng)險,警報用
error():操作沒有成功或者某些事情失敗
debug():在生產(chǎn)環(huán)境中這種messages會移除或者忽略
創(chuàng)建一個定制的認(rèn)證(authentication)后臺
Django允許你通過不同的來源進行認(rèn)證(authentication)牍白。AUTHENTICATION_BACKENDS設(shè)置包含了所有的給你的項目的認(rèn)證(authentication)后臺脊凰。
1.('django.contrib.auth.backends.ModelBackend',)---默認(rèn)的ModelBackend通過數(shù)據(jù)庫使用django.contrib.auth中的User模型(model)來認(rèn)證(authentication)用戶。
2.當(dāng)你使用django.contrib.auth的authenticate()函數(shù)茂腥,Django會通過每一個定義在AUTHENTICATION_BACKENDS中的后臺一個接一個地嘗試認(rèn)證(authentication)用戶狸涌,直到其中有一個后臺成功的認(rèn)證該用戶才會停止進行認(rèn)證。只有所有的后臺都無法進行用戶認(rèn)證(authentication)最岗,他或她才不會在你的站點中通過認(rèn)證(authentication)帕胆。
Django提供了一個簡單的方法來定義你自己的認(rèn)證(authentication)后臺。一個認(rèn)證(authentication)后臺就是提供了如下兩種方法的一個類:
authenticate():將用戶信息當(dāng)成參數(shù)般渡,如果用戶成功的認(rèn)證(authentication)就需要返回True懒豹,反之,需要返回False驯用。
get_user():將用戶的ID當(dāng)成參數(shù)然后需要返回一個用戶對象
創(chuàng)建一個定制認(rèn)證(authentication)后臺非常容易,就是編寫一個Python類實現(xiàn)上面兩個方法。我們要創(chuàng)建一個認(rèn)證(authentication)后臺讓用戶在我們的站點中使用他們e-mail替代他們的用戶名來進行認(rèn)證(authentication)固惯。
class EmailAuthBackend(object):
????????def authenticate(self, username=None, password=None):
????????????????try:
????????????????????????user = User.objects.get(email=username)
????????????????????????if user.check_password(password):
????????????????????????????????return user
????????????????????????return None
????????????????except User.DoesNotExist:
????????????????????????return None
????????def get_user(self, user_id):
????????????????try:
????????????????????????return User.objects.get(pk=user_id)
????????????????except User.DoesNotExist:
????????????????????????return None
authenticate():我們嘗試通過給予的e-mail地址獲取一個用戶和使用User模型(model)中內(nèi)置的check_password()方法來檢查密碼。這個方法會對給予密碼進行哈系裱兀化來和數(shù)據(jù)庫中存儲的加密密碼進行匹配审轮。
get_user():我們通過user_id參數(shù)獲取一個用戶断国。Django使用這個后臺來認(rèn)證用戶之后取回User對象放置到持續(xù)的用戶會話中。