手機號或者賬號用於登陸
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方法