django 自定義登入驗證邏輯

__奇犽犽發表於2018-01-31

本文的django view採用的是基於cbv的模式

django中的登入功能主要涉及到django.contrib.auth這個包,它提供了2個重要的函式:authenticate和login。

django.contrib.auth.authenticate

這個函式接受的一個收集引數,但至少需要接受username和password這兩個關鍵引數,它完成以下的事情:

  1. 從setting中獲取AUTHENTICATION_BACKENDS的元組, 預設情況下是django.contrib.auth.backends.ModelBackend.
  2. 遍歷這整個元組,然後呼叫每一個Backend的authenticate方法,而每個Backend.authenticate會有一個登陸邏輯(自定義後面會提及),如ModelBackend.authenticate它拿傳過來的賬號密碼的與資料庫user model的username與password進行驗證。
  3. 如果Backend.authenticate驗證通過,就會返回一個user物件,然後auth.authenticate將不再進行遍歷,return user物件。如果返回None,就繼續呼叫下一個Backend.authenticate。如果全部都返回None,那麼驗證不通過。

django.contrib.auth.login

login只會用在auth.authenticate返回一個user的情況下,這個函式會接著做下面的事情:

  1. 生成一個新的session_id 放到request.session中(這個session在返回時會被session的中介軟體進行處理,將session_id放入到cookie當中)
  2. 將這個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,也可以是手機/郵箱等,這時候,我們可以進行一個自定義的登入邏輯驗證。

  1. 首先在view中寫自己的Backend,最好直接繼承ModelBackend
  2. 過載authenticate方法,引數直接來自auth.authenticate,但因為驗證需要用到表單中的username和password,所以前面提到,auth.authenticate也至少去接受這兩個關鍵引數
  3. 用Q方法可以在進行或操作,如果用','是使用與操作,由於資料庫中的password是加密的,不能直接使用password=password,django為我們提供了check_password方法進行驗證。
  4. 如果驗證通過需要返回user物件,否則返回None
  5. 在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函式主要完成:

  1. 將request.session清除
  2. request.user = AnonymousUser()將使用者設定與匿名使用者

相關文章