跳转到主内容
websoft网络软件专家 - 深耕网络技术,打造实用软件!

Python Django如何实现用户自定义登录校验_继承AbstractUser模型并重写认证后台

直接继承AbstractUser不能解决自定义登录校验,因其仅定义字段结构,不参与认证逻辑;Django登录由authenticate()调用AuthenticationBackend完成,与模型继承无关,必须自定义后台类并注册到AUTHENTICATION_BACKENDS首位。 为什么直接继承
AbstractUser
不能解决自定义登录校验? 因为
AbstractUser
只定义了用户字段结构,不参与认证逻辑;Django 的登录流程由
authenticate()
调用认证后台(
AuthenticationBackend
)完成,和模型继承无关。哪怕你重写了
check_password
或加了自定义字段,只要后台没改,
authenticate()
仍按默认规则(用户名+密码)查
User
模型,根本不会走到你的逻辑里。 常见错误现象:
authenticate(username='xxx', password='yyy')
返回
None
,但数据库里明明有该用户;或者登录成功了,却没触发你写的邮箱验证、状态检查等逻辑。 必须实现一个继承
ModelBackend
的自定义后台类 在
settings.py
中显式注册它,覆盖默认后台 重写
authenticate()
方法,在其中调用你自己的校验逻辑(比如支持邮箱/手机号登录、检查
is_active
细粒度状态、临时冻结等) 如何写一个支持邮箱或手机号登录的认证后台? 核心是重写
authenticate()
:解析传入的
username
参数,判断它是邮箱、手机号还是用户名,再用对应字段查库。注意别硬编码字段名,要用
get_by_natural_key()
或
filter()
配合
Q
查询。
from django.contrib.auth.backends import ModelBackend from django.contrib.auth import get_user_model from django.db.models import Q

class EmailOrPhoneBackend(ModelBackend): def authenticate(self, request, username=None, password=None, **kwargs): UserModel = get_user_model() try:

先尝试邮箱

        user = UserModel.objects.get(Q(email=username) | Q(phone=username) | Q(username=username))
    except UserModel.DoesNotExist:
        return None
    if user.check_password(password) and self.user_can_authenticate(user):
        return user
    return None
立即学习 “ Python免费学习笔记(深入) ”; 关键点: go语言参考手册 中文CHM版 Go 是一个开源的编程语言,它能让构造简单、可靠且高效的软件变得容易。本文给大家带来Go参考手册,需要的可以来下载! Go是从2007年末由Robert Griesemer, Rob Pike, Ken Thompson主持开发,后来还加入了Ian Lance Taylor, Russ Cox等人,并最终于2009年11月开源,在2012年早些时候发布了Go 1稳定版本。现在Go的开发已经是完全开放的,并且拥有一个活跃的社区。 Go 语言特色 简洁、快速、安全 并行、有趣、开源 内存管理、v数组安全、编译 下载
self.user_can_authenticate(user)
是
ModelBackend
自带方法,会检查
is_active
和
is_staff
(如果启用了
require_staff_status
),建议保留 不要在
authenticate()
里抛异常,返回
None
即可,Django 登录视图会安静处理 如果用了自定义字段(如
phone
),确保该字段在模型中已定义且允许为空或有唯一约束,否则查库可能出错 settings.py 中怎么正确配置认证后台? 必须把自定义后台放在
AUTHENTICATION_BACKENDS
列表首位,Django 按顺序调用每个后台的
authenticate()
,只要有一个返回用户对象就终止。如果放后面,可能被默认后台提前“截胡”——比如用户名匹配成功,但你本意是让邮箱优先。 配置示例(假设后台文件在
myapp/auth_backends.py
):
AUTHENTICATION_BACKENDS = [ 'myapp.auth_backends.EmailOrPhoneBackend', 'django.contrib.auth.backends.ModelBackend', # 保留默认,作为兜底 ]
容易踩的坑: 路径写错(比如漏了
myapp.
或模块名大小写不符),导致启动时报
ImproperlyConfigured
忘记保留
ModelBackend
,导致管理后台(
/admin/
)无法登录 多个后台共存时,不同后台对同一
username
的解释冲突(比如一个按邮箱查,一个按用户名查),引发不可预期行为 继承
AbstractUser
后还要注意什么? 主要是字段兼容性和迁移问题。Django 默认的
User
模型字段(如
username
、
email
)在
AbstractUser
里已定义,如果你要改字段行为(比如让
email
成为主键、取消
username
必填),不能只改模型声明,还得同步调整认证后台里的查询逻辑和表单验证。 若设
email
为唯一且非空,记得在后台里把
username
字段查询删掉,否则查不到用户 新增字段(如
is_email_verified
)要在
authenticate()
里显式检查,Django 不会自动拦截 运行
python manage.py makemigrations
前确认已有数据能兼容新字段约束,否则迁移会卡住 最常被忽略的是:后台类里查库用的字段,必须和模型实际字段一致;而模型字段是否生效,又取决于迁移是否成功执行——这两步脱节,调试时容易绕晕。

相关文章