参考文章

https://juejin.im/post/5d17247ce51d451061721118

django默认的用户验证方式是用户名+密码的形式

如果是手机验证码登录方式显然不合适,所以,需要自定义用户认证类

django默认的authentication

class ModelBackend(BaseBackend):
    """
    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)
        if username is None or password is None:
            return
        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 nonexistent user (#20760).
            UserModel().set_password(password)
        else:
            if user.check_password(password) and self.user_can_authenticate(user):
                return user

所以可以继承ModelBackend这个类,覆写authenticate方法

默认有两个参数usernamepassword

username = kwargs.get(UserModel.USERNAME_FIELD)这一句是获取用户名字段

django中,用户名字段就是username,如果用户的手机号码就是username字段,那就不用修改

但是常规来说,电话号码和用户名字段都是分开的,也会不相同

我这里重写了用户模型,新增字段tel

此时应该改成这样了

username = kwargs.get("tel")

你可以不用写的这么死,你只需要在User模型覆盖重写

USERNAME_FIELD = "tel"

这句就不做任何改变

username = kwargs.get(UserModel.USERNAME_FIELD)

在官方的authentication方法中,用于校验密码是否正确的方法是check_password

我们也可以在我们自己的User模型中,定义一个校验密码是否正确的方法

下面是我重写后的样子

# 导入这个类
from django.contrib.auth.backends import ModelBackend
# 导入获取用户模型的方法
from django.contrib.auth import get_user_model

UserModel = get_user_model()

class CustomModelBackends(ModelBackend):

    def authenticate(self, request, username=None, password=None, **kwargs):
        if username is None:
            username = kwargs.get(UserModel.USERNAME_FIELD)
        if username is None or password is None:
            return
        try:
            # 判断数据库内是否有这个用户
            user = UserModel._default_manager.get_by_natural_key(username)
        except UserModel.DoesNotExist:
            # 不存在此用户则创建
            user = UserModel.objects.create_user(username=username, tel=username)
        # 判断当前用户是否是网站管理员
        if user.is_staff:
            if user.check_password(password) and self.user_can_authenticate(user):
                return user
        else:
            # 校验验证码和手机号码是否正确
            res = user.check_verify_code(username, password)
            if res['status'] and self.user_can_authenticate(user):
                user.cookie = res['cookies']
                user.save()
                return user

这里我加了一个判断用户是否是网站管理员,管理员是用账号密码登录,普通用户是用手机验证码登录

我这里的实际需求就是这样的,所以看着有点怪异

覆盖重写后,要让其生效,需要修改settings

# 写上自己的用户模型路径,不写的话,就用用django默认的
AUTH_USER_MODEL = 'user.User'

# 用于验证用户密码是否正确的类,填写上面覆盖重写后的类
AUTHENTICATION_BACKENDS = [
    'user.backends.CustomModelBackends'
]

在视图函数中使用时,就和之前都是一样的了

# ...
# 验证账号密码是否正确
user = auth.authenticate(request, username=username, password=password)
# ...
# 为用户设置登录状态
auth.login(request, user)
# ...
Last modification:May 4th, 2020 at 12:07 pm