如何在Django自定义UserAuthentication模型中校验用户是否存在
问题原因
- Django默认的
authenticate认证方法会读取内置auth.User表,没有配置自定义用户模型的前提下不会查询你写的UserAuthentication表 - 现有
UserAuthentication直接继承models.Model,没有兼容Django认证体系的基础字段和方法,无法和自带的authenticate、login方法适配 - 视图中
if user is UserAuthentication逻辑错误:is用于判断两个对象的内存地址是否一致,user是用户实例,UserAuthentication是模型类,二者永远不相等 - 密码明文存储在
password1字段中,authenticate方法默认会将传入的密码做哈希加密后和数据库存储的哈希值对比,明文密码永远无法通过校验
修复步骤
1. 修改自定义用户模型(models.py)
继承Django提供的AbstractBaseUser和PermissionsMixin获得认证体系兼容能力,删除冗余的明文密码字段,新增用户管理器:
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, BaseUserManager from django.db import models class UserManager(BaseUserManager): def create_user(self, username, email, password=None, **extra_fields): if not username: raise ValueError('用户名必须填写') if not email: raise ValueError('邮箱必须填写') email = self.normalize_email(email) user = self.model(username=username, email=email, **extra_fields) user.set_password(password) user.save(using=self._db) return user def create_superuser(self, username, email, password=None, **extra_fields): extra_fields.setdefault('is_staff', True) extra_fields.setdefault('is_superuser', True) return self.create_user(username, email, password, **extra_fields) class UserAuthentication(AbstractBaseUser, PermissionsMixin): username = models.CharField(max_length=100, unique=True, verbose_name="用户名") email = models.EmailField(unique=True, verbose_name="邮箱") is_active = models.BooleanField(default=True) is_staff = models.BooleanField(default=False) objects = UserManager() # 指定用户名字段,authenticate方法会用该字段匹配用户 USERNAME_FIELD = 'username' REQUIRED_FIELDS = ['email'] def __str__(self): return self.username
2. 配置settings.py指定自定义用户模型
添加配置项,告知Django使用你定义的用户表替换内置User表,替换代码中你的应用名为实际存放UserAuthentication模型的app名称:
AUTH_USER_MODEL = '你的应用名.UserAuthentication'
3. 修改视图逻辑(views.py)
修正用户判断逻辑:
def loginpage(request): if request.method == "POST": username = request.POST.get('username') password = request.POST.get('password') user = authenticate(request, username=username, password=password) if user is not None: login(request, user) return redirect('index') else: messages.warning(request, "用户名或密码错误!") return redirect('login') else: return render(request, "HTML/login.html", context={})
4. 数据迁移与注意事项
- 修改完用户模型后需要删除之前的迁移文件和数据库文件,重新执行
python manage.py makemigrations和python manage.py migrate,避免迁移冲突 - 注册逻辑中校验两次密码一致后,调用
user.set_password(明文密码)方法加密存储密码,不要直接给password字段赋值明文 - 原有明文存储的旧用户数据需要重新创建,否则无法通过密码校验
内容的提问来源于stack exchange,提问作者Subhan Malik
相关产品推荐
相关产品推荐

