本文的django view採用的是基於cbv的模式
django中的登入功能主要涉及到django.contrib.auth這個包,它提供了2個重要的函式:authenticate和login。
django.contrib.auth.authenticate
這個函式接受的一個收集引數,但至少需要接受username和password這兩個關鍵引數,它完成以下的事情:
- 從setting中獲取AUTHENTICATION_BACKENDS的元組, 預設情況下是django.contrib.auth.backends.ModelBackend.
- 遍歷這整個元組,然後呼叫每一個Backend的authenticate方法,而每個Backend.authenticate會有一個登陸邏輯(自定義後面會提及),如ModelBackend.authenticate它拿傳過來的賬號密碼的與資料庫user model的username與password進行驗證。
- 如果Backend.authenticate驗證通過,就會返回一個user物件,然後auth.authenticate將不再進行遍歷,return user物件。如果返回None,就繼續呼叫下一個Backend.authenticate。如果全部都返回None,那麼驗證不通過。
django.contrib.auth.login
login只會用在auth.authenticate返回一個user的情況下,這個函式會接著做下面的事情:
- 生成一個新的session_id 放到request.session中(這個session在返回時會被session的中介軟體進行處理,將session_id放入到cookie當中)
- 將這個user放到request.user中
講了那麼多,我們來看一下程式碼:
class LoginView(View):
def get(self, request):
pass
def post(self, request):
username = request.POST.get('username', '')
password = request.POST.get('password', '')
login_form = LoginForm(request.POST)
if login_form.is_valid:
user = auth.authenticate(username=username, password=password)
if user is not None:
login(request, user)
# 如果登入成功,重定向要主頁
return HttpResponseRedirect(reverse('index'))
else:
# user為None,說明賬號或密碼錯誤
return render(request, "login.html", {"msg": "使用者名稱或密碼錯誤"})
else:
# 表單無效,返回login_form物件即可,在template呼叫login_form.errors這個字典去獲取相關的錯誤
return render(request, "login.html", {"login_form": login_form})
複製程式碼
顯然,如果單純使用ModelBackend.authenticate的驗證邏輯是不能滿足我們的需求,我們登入的賬號可以是username,也可以是手機/郵箱等,這時候,我們可以進行一個自定義的登入邏輯驗證。
- 首先在view中寫自己的Backend,最好直接繼承ModelBackend
- 過載authenticate方法,引數直接來自auth.authenticate,但因為驗證需要用到表單中的username和password,所以前面提到,auth.authenticate也至少去接受這兩個關鍵引數
- 用Q方法可以在進行或操作,如果用','是使用與操作,由於資料庫中的password是加密的,不能直接使用password=password,django為我們提供了check_password方法進行驗證。
- 如果驗證通過需要返回user物件,否則返回None
- 在setting中配置
# app+views+backend名字
AUTHENTICATION_BACKENDS = (
'users.views.MyUserBackend',
)
複製程式碼
from django.db.models import Q
from django.contrib.auth.hashers import make_password
class MyUserBackend(ModelBackend):
"""
自定義使用者驗證
"""
def authenticate(self, username=None, password=None, **kwargs):
try:
user = UserProfile.objects.get(Q(username=username) | Q(email=username) | Q(mobile=username))
if user.check_password(password):
return user
except Exception as e:
return None
複製程式碼
django.contrib.auth.logout
順便提及一下logout函式,由於django已經為我們提供好了退出的處理,使用起來十分簡單:
class LogoutView(View):
def get(self, request):
logout(request)
return HttpResponseRedirect(reverse('index'))
複製程式碼
logout函式主要完成:
- 將request.session清除
- request.user = AnonymousUser()將使用者設定與匿名使用者