Django多方式登录认证

发布时间 2023-08-05 13:57:40作者: hkwJsxl

原理

我们平常使用的Django登录认证是django.contrib.auth.authenticate

image-20230805124610375

点进去源码,我们会看到这个函数,真正的认证类是它里面的那个

image-20230805124703088

继续点进去源码,会看到ModelBacked类,内部是用户名登录认证校验,它上一层就是基类了,所以我们只要重写这个类的authenticate函数即可。

image-20230805124747862

实现

第一步,写一个函数,继承ModelBackend类,authenticate.py

import re

from django.contrib.auth.backends import ModelBackend

from users.models import UserInfo


class ReModelBackend(ModelBackend):
    """登录多方式认证类(支持手机号和用户名登录)"""

    def authenticate(self, request, username=None, password=None, **kwargs):
        """重写authenticate方法"""
        user = self.user_or_none(username)
        if user and user.check_password(password):
            return user
        else:
            return None

    def user_or_none(self, account):
        """
        自定义方法
        account: 用户名或手机号
        return: user对象或None
        """
        is_match = re.match(r"1[3-9]\d{9}$", account)
        try:
            if is_match:
                user = UserInfo.objects.get(mobile=account)
            else:
                user = UserInfo.objects.get(username=account)
        except:
            return None
        else:
            return user

第二步,Django配置,settings.py

# 列表内是导包路径
AUTHENTICATION_BACKENDS = ['extension.authenticate.ReModelBackend']

Django全局配置中也可以看到配置项

image-20230805134835504

第三步,调用,登录视图示例,users/views.py

from django.shortcuts import render, HttpResponse, redirect, reverse
from django.views import View
from django.contrib.auth import login, authenticate

from .forms import LoginForm
from .models import UserInfo

class LoginView(View):
    """登录视图"""

    def get(self, request):
        return render(request, "login.html")

    def post(self, request):
        form_obj = LoginForm(request.POST)
        if not form_obj.is_valid():
            return render(request, "login.html", {"return_msg": "数据校验失败."})
        username = form_obj.cleaned_data.get("username")
        password = form_obj.cleaned_data.get("password")
        remembered = form_obj.cleaned_data.get("remembered")
        # 多方式认证登录
        user = authenticate(username=username, password=password)
        if not user:
            return render(request, "login.html", {"return_msg": "用户名或密码错误."})
        login(request, user)
        # 设置失效时间
        if not remembered:
            request.session.set_expiry(0)
        else:
            request.session.set_expiry(None)
        return redirect(reverse("contents:index"))

登录表单认证,users/forms.py

from django import forms

from .models import UserInfo


class LoginForm(forms.Form):
    username = forms.CharField(max_length=20, min_length=5, required=True, label="用户名", error_messages={
        "max_length": "用户名最大长度为20",
        "min_length": "用户名最小长度为5",
        "required": "用户名不能为空"
    })
    password = forms.CharField(max_length=20, min_length=8, required=True, label="密码", error_messages={
        "max_length": "密码最大长度为20",
        "min_length": "密码最小长度为8",
        "required": "密码不能为空"
    })
    remembered = forms.BooleanField(required=False)