Django自定义认证支持邮箱/用户名登录却无法登录,求原因排查
Django 邮箱/用户名双登录认证失败排查
问题背景
开发Django认证项目,目标实现用户通过邮箱或用户名登录。自定义用户模型、管理器及认证后端代码如下,但创建超级用户流程正常,登录认证始终失败。
自定义用户模型
class LinksUser(AbstractBaseUser, PermissionsMixin): objects = LinksUserManager() full_name = models.CharField(max_length=200, blank=False) email = models.EmailField(_("email address"), unique=True) username = models.CharField(_("username"), unique=True, max_length=20) is_active = models.BooleanField(default=False) is_staff = models.BooleanField(default=False) USERNAME_FIELD = "username" EMAIL_FIELD = "email" REQUIRED_FIELDS = ['email'] def __str__(self): return self.email
自定义用户管理器
class LinksUserManager(BaseUserManager): """ Custom user-model manager where the email and username are identifiers for authentication """ def create_user(self, email, username, password, **extra_fields): if not username: raise ValueError('Username must be set') if not email: raise ValueError('Email must be set') email = self.normalize_email(email) user = self.model(username=username, email=email) 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) if extra_fields.get('is_staff') is not True: raise ValueError(_('Superuser must have is_staff=True.')) if extra_fields.get('is_superuser') is not True: raise ValueError(_('Superuser must have is_superuser=True.')) return self.create_user(username, email, password, **extra_fields)
自定义认证后端
from .models import LinksUser class LinkUserBackend(object): """ Model backend that attempts to allow a user to log in with either the username or the email address """ def authenticate(self, request, username=None, password=None): try: user = LinksUser.objects.get(email=username) except LinksUser.DoesNotExist: try: user = LinksUser.objects.get(username=username) except LinksUser.DoesNotExist: return None if user.check_password(password): return user
可能的原因及解决方法
1. 自定义认证后端未配置到settings
Django默认使用django.contrib.auth.backends.ModelBackend,未将自定义后端加入配置的话,系统不会用它处理登录请求。
解决方法:在settings.py中添加:
AUTHENTICATION_BACKENDS = [ 'your_app_name.backends.LinkUserBackend', # 替换为实际的后端路径 ]
2. 认证后端缺少get_user方法
Django要求认证后端必须实现get_user方法,用于登录后获取用户对象,缺失会导致认证失败。
解决方法:在LinkUserBackend中补充方法:
def get_user(self, user_id): try: return LinksUser.objects.get(pk=user_id) except LinksUser.DoesNotExist: return None
3. 创建超级用户时参数顺序错误
create_superuser调用create_user时,将username和email的传参顺序搞反了,导致用户数据存储错误(邮箱字段存了用户名,用户名字段存了邮箱),登录时无法匹配正确用户。
解决方法:修正create_superuser中的调用代码:
return self.create_user(email, username, password, **extra_fields)
4. 用户is_active状态为False
自定义用户模型中is_active默认是False,未激活的用户无法登录。超级用户创建时也未显式设置is_active=True,导致超级用户同样处于未激活状态。
解决方法:
- 在
create_user方法中默认设置激活状态:def create_user(self, email, username, password, **extra_fields): # ... 原有代码 extra_fields.setdefault('is_active', True) user = self.model(username=username, email=email, **extra_fields) # ... 原有代码 - 或在
create_superuser中单独设置:def create_superuser(self, username, email, password=None, **extra_fields): extra_fields.setdefault('is_staff', True) extra_fields.setdefault('is_superuser', True) extra_fields.setdefault('is_active', True) # 添加这一行 # ... 原有代码
5. 认证后端继承错误
自定义后端应继承django.contrib.auth.backends.BaseBackend而非直接继承object,否则可能引发兼容性问题。
解决方法:修改后端继承:
from django.contrib.auth.backends import BaseBackend class LinkUserBackend(BaseBackend): # ... 原有代码
内容的提问来源于stack exchange,提问作者Juan Monster
相关产品推荐
相关产品推荐

