多途徑用戶登陸的實現

手機號或者賬號用於登陸

Django自帶的用戶認證後端默認是使用用戶名實現用戶認證的

用戶認證後端位置:django.contrib.auth.backends.ModelBackend

class ModelBackend(object):
    """
    Authenticates against settings.AUTH_USER_MODEL.
    """

    def authenticate(self, request, username=None, password=None, **kwargs):
        if username is None:
            username = kwargs.get(UserModel.USERNAME_FIELD)
        try:
            user = UserModel._default_manager.get_by_natural_key(username)
        except UserModel.DoesNotExist:
            # Run the default password hasher once to reduce the timing
            # difference between an existing and a non-existing user (#20760).
            UserModel().set_password(password)
        else:
            if user.check_password(password) and self.user_can_authenticate(user):
                return user
user = UserModel._default_manager.get_by_natural_key(username)

這一句可以簡單理解爲:

user = User.objects.get(username=username)

視圖views.py

from django.contrib.auth import login, authenticate
from users.models import User


class LoginView(View):
    """用戶登陸"""

    def get(self, request):
        """提供用戶登陸頁面"""
        return render(request, 'login.html')

    def post(self, request):
        """實現用戶登陸邏輯"""
        # 接收參數
        username = request.POST.get('username')
        password = request.POST.get('password')
        remembered = request.POST.get('remembered')

        # 校驗參數
        if not all([username, password]):
            return http.HttpResponseForbidden('缺少必傳參數')

        # 校驗用戶名
        if not re.match(r'^[a-zA-Z0-9_-]{5,20}$', username):
            return http.HttpResponseForbidden('請輸入正確的用戶名或手機號')

        # 檢驗密碼
        if not re.match(r'^[0-9A-Za-z]{8,20}$', password):
            return http.HttpResponseForbidden('密碼最少8位,最長20位')
        # 認證用戶:使用賬號查詢用戶是否存在,如果用戶存在,再檢驗密碼是否正確
        # user = User.objects.get(username=username)
        # user.check_password()
        user = authenticate(username=username, password=password)
        if user is None:
            return render(request, 'login.html', {'account_errmsg': '賬號或密碼錯誤'})
        # 狀態保持
        login(request, user)
        if remembered != 'on':
            # 沒有記住登陸: 狀態保持在瀏覽器會話結束後就銷燬
            request.session.set_expiry(0)   # 單位是秒
        else:
            # 記住登陸:狀態保持週期爲兩週(默認是兩週)
            request.session.set_expiry(3600)

        # 響應結果: 重定向到首頁
        return redirect(reverse('contents:index'))

由於Django自帶的用戶認證後端默認是使用用戶名實現用戶認證的,如果要使用手機號做認證,需要重新定義authenticate方法。

新建文件utils.py

# 自定義用戶認證的後端:實現多賬號登陸
from django.contrib.auth.backends import ModelBackend
import re

from users.models import User


def get_user_by_account(account):
    """
    通過賬號獲取用戶
    :param account: 用戶名或者手機號
    :return: user
    """
    try:
        if re.match(r'^1[3-9]\d{9}$', account):
            # username == 手機號
            user = User.objects.get(mobile=account)
        else:
            # username == 用戶名
            user = User.objects.get(username=account)
    except User.DoesNotExist:
        return None
    else:
        return user


class UsernameMobileBackend(ModelBackend):
    """自定義用戶認證後端"""

    def authenticate(self, request, username=None, password=None, **kwargs):
        """
        重寫用戶認證的方法
        :param request:
        :param username: 用戶名或手機號
        :param password: 密碼明文
        :param kwargs: 額外參數
        :return: user
        """
        # 查詢用戶
        user = get_user_by_account(username)
        # 如果可以查詢到用戶,還需要校驗密碼是否正確
        if user and user.check_password(password):
        # 返回user
            return user
        else:
            return None

並且在項目配置文件中指定新的AUTHENTICATION_BACKENDS

# 指定自定義用戶認證的後端
AUTHENTICATION_BACKENDS = ['users.utils.UsernameMobileBackend']

下面分析流程:

views.py的53行打斷點

utils.py的14行打斷點

後端接收到用戶名和明文密碼

放通斷點

發現調用的是utils.py中自定義的authenticate方法

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章