使用自定义User模型实现Django认证时用户变为Anonymous User问题求助
嘿,我明白你在学校项目里用自定义User模型实现Django认证时碰到了用户变成Anonymous User的麻烦,这在自定义认证模型时确实是个高频踩坑点,我来帮你梳理下可能的原因和解决办法!
首先,先看你给出的代码片段,能发现几个关键问题,再结合Django自定义用户模型的要求,我们一步步来修正:
1. 必须正确配置AUTH_USER_MODEL
这是最基础却最容易忘的一步!在你的项目settings.py里,一定要添加这行配置,告诉Django使用你的自定义用户模型:
AUTH_USER_MODEL = "你的应用名.User" # 比如如果你的User模型在名为accounts的app里,就写"accounts.User"
如果没加这行,Django会默认使用自带的User模型,自然无法识别你的自定义用户,导致登录后还是匿名。
2. 修正User模型的核心问题
你的自定义User模型继承了AbstractBaseUser,但缺少几个必要的配置和方法:
(1)删除重复的password字段
AbstractBaseUser已经自带了password字段,并且Django会自动处理密码的哈希存储。你自己定义的password = models.CharField(max_length=24)会覆盖这个逻辑,导致密码无法正确验证,登录失败后就会变成匿名用户,必须删掉这一行。
(2)添加自定义UserManager
AbstractBaseUser没有默认的对象管理器,你必须定义一个UserManager来处理用户的创建逻辑(包括普通用户和超级用户),否则无法创建用户、无法用createsuperuser命令:
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager class UserManager(BaseUserManager): def create_user(self, username, first_name, last_name, password=None): # 校验必填字段 if not username: raise ValueError("用户名不能为空") if not first_name: raise ValueError("名字不能为空") if not last_name: raise ValueError("姓氏不能为空") # 创建用户实例 user = self.model( username=username, first_name=first_name, last_name=last_name ) # 用Django内置的set_password处理密码哈希 user.set_password(password) user.save(using=self._db) return user def create_superuser(self, username, first_name, last_name, password): # 复用create_user方法创建超级用户,再添加权限 user = self.create_user( username=username, first_name=first_name, last_name=last_name, password=password ) # 添加必要的权限字段,根据你的需求调整 user.is_admin = True user.is_active = True user.save(using=self._db) return user
然后在你的User模型里添加:
class User(AbstractBaseUser): userID = models.AutoField(primary_key=True) username = models.CharField(max_length=20, unique=True) first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=50) # 添加必要的权限状态字段 is_active = models.BooleanField(default=True) # 用户是否激活 is_admin = models.BooleanField(default=False) # 是否是管理员 USERNAME_FIELD = "username" REQUIRED_FIELDS = ["first_name", "last_name"] # 绑定自定义管理器 objects = UserManager() # 实现Django认证系统要求的方法 def get_full_name(self): return f"{self.first_name} {self.last_name}" def get_short_name(self): return self.first_name # 权限相关方法,Django后台需要这些 def has_perm(self, perm, obj=None): # 简单逻辑:管理员拥有所有权限 return self.is_admin def has_module_perms(self, app_label): # 简单逻辑:管理员能访问所有应用 return self.is_admin @property def is_staff(self): # 定义哪些用户能登录Django后台,这里让管理员都能登录 return self.is_admin
3. 检查登录逻辑是否正确
确保你的登录视图里正确使用了Django的authenticate和login函数,这两个步骤缺一不可:
from django.contrib.auth import authenticate, login from django.shortcuts import redirect, render def login_view(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("你的首页路由") # 登录成功后跳转 else: # 登录失败的提示 return render(request, "login.html", {"error": "用户名或密码错误"}) return render(request, "login.html")
如果跳过了login(request, user),或者authenticate返回None(比如密码不匹配),都会导致用户保持匿名状态。
4. 确认中间件配置完整
在settings.py的MIDDLEWARE里,必须包含以下两个中间件,它们负责处理用户会话和认证:
MIDDLEWARE = [ # ... 其他中间件 "django.contrib.sessions.middleware.SessionMiddleware", "django.contrib.auth.middleware.AuthenticationMiddleware", # ... 其他中间件 ]
如果缺失这两个,Django无法跟踪用户会话,自然识别不了登录后的用户。
5. 重置数据库迁移(如果之前有错误迁移)
如果你是中途修改的用户模型,可能存在迁移冲突。最简单的解决方式是:
- 删除项目根目录的
db.sqlite3文件(如果用的是SQLite) - 删除你的应用下
migrations文件夹里除了__init__.py以外的所有文件 - 重新执行迁移命令:
python manage.py makemigrations python manage.py migrate
然后用python manage.py createsuperuser创建一个超级用户,测试登录Django后台是否正常。
按照这些步骤调整后,你的自定义用户模型应该就能正常工作,不会再出现Anonymous User的问题啦!
内容的提问来源于stack exchange,提问作者jcannell

