You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django自定义认证失效:用户与Agent均无法登录求助

Django双用户系统登录失败问题修复方案

问题概述

开发Django网站时设置了独立的CustomUser和Agent用户模型,Agent无需注册为User即可独立注册。注册时密码已在Admin面板确认被正确哈希,但两类用户登录均失败,提示“请输入正确的用户名和密码。注意两个字段均区分大小写。”

核心错误点及修复

1. Agent模型手动定义password字段,破坏AbstractBaseUser密码管理逻辑

AbstractBaseUser已内置密码管理机制,手动添加password = models.CharField(max_length=200)会覆盖原有字段,导致密码验证异常。同时agent_email应使用EmailField而非CharField,last_login需改为auto_now以记录每次登录时间。

修复models.py中Agent类:

class Agent(AbstractBaseUser, PermissionsMixin):
    username = models.CharField(max_length=100, unique=True)
    name = models.CharField(max_length=100)
    agent_email = models.EmailField(unique=True)  # 修正字段类型
    # 移除手动定义的password字段
    image = models.ImageField(upload_to='Images/')
    bio = models.TextField()
    instagram = models.URLField(max_length=100)
    twitter = models.URLField(max_length=100)
    facebook = models.URLField(max_length=100)
    linkedin = models.URLField(max_length=100)
    is_featured = models.BooleanField(default=False)
    last_login = models.DateTimeField(auto_now=True)  # 修正登录时间更新逻辑
    is_active = models.BooleanField(default=True)
    slug = AutoSlugField(populate_from='name')
    is_staff = models.BooleanField(default=False)
    groups = models.ManyToManyField(Group, related_name='agent_set', blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.')
    user_permissions = models.ManyToManyField(Permission, related_name='agent_set', blank=True, help_text='Specific permissions for this user.')

    objects = AgentManager()

    USERNAME_FIELD = 'username'
    EMAIL_FIELD = 'agent_email'

    def get_absolute_url(self):
        return reverse('agent-dashboard', kwargs={'slug': self.slug})

    def __str__(self):
        return self.name

2. 认证后端get_user方法未处理Agent用户

原CustomAuthBackend的get_user仅查找CustomUser,登录Agent后系统无法识别该用户,导致后续验证失败。同时Agent的用户名/邮箱匹配应改为不区分大小写,与User逻辑保持一致。

修复backends.py:

from django.contrib.auth.models import Group, Permission
from .models import Agent
UserModel = get_user_model()

class CustomAuthBackend(ModelBackend):
    def authenticate(self, request, username=None, password=None, **kwargs):
        user_type = kwargs.pop('user_type', None)

        if user_type == 'user':
            try:
                user = UserModel.objects.get(Q(username__iexact=username) | Q(email__iexact=username))
            except UserModel.DoesNotExist:
                return None

            if user.check_password(password) and self.user_can_authenticate(user):
                return user

        elif user_type == 'agent':
            try:
                # 改为不区分大小写匹配用户名/邮箱
                agent = Agent.objects.get(Q(username__iexact=username) | Q(agent_email__iexact=username))
            except Agent.DoesNotExist:
                return None

            if agent.check_password(password) and self.user_can_authenticate(agent):
                return agent

    def get_user(self, user_id):
        # 先查找CustomUser,再查找Agent
        try:
            return UserModel.objects.get(pk=user_id)
        except UserModel.DoesNotExist:
            try:
                return Agent.objects.get(pk=user_id)
            except Agent.DoesNotExist:
                return None

3. 自定义登录表单需指定对应模型,避免默认验证逻辑冲突

原UserSignInForm和AgentSignInForm继承AuthenticationForm,默认使用AUTH_USER_MODEL验证,需重写get_user_model方法指定对应模型,并调整Agent表单的clean逻辑。

修复forms.py:

from django.contrib.auth.forms import AuthenticationForm
from .models import Agent, CustomUser

class UserSignInForm(AuthenticationForm):
    user_type = forms.CharField(initial='user', widget=forms.HiddenInput(), required=False)

    def get_user_model(self):
        return CustomUser

class AgentSignInForm(AuthenticationForm):
    user_type = forms.CharField(initial='agent', widget=forms.HiddenInput(), required=False)

    def get_user_model(self):
        return Agent

    # 重写clean方法,避免默认验证逻辑报错
    def clean(self):
        username = self.cleaned_data.get('username')
        password = self.cleaned_data.get('password')

        if username and password:
            pass  # 验证逻辑留给后端处理
        return self.cleaned_data

4. Agent注册/登录视图的后端指定错误及slug获取时机问题

原AgentRegisterView中登录时指定的后端不存在,AgentLoginView中登录成功前无法获取self.request.user.slug。

修复views.py:

class AgentRegisterView(CreateView):
    template_name = 'users/agent_register.html'
    form_class = AgentRegisterForm
    model = Agent

    def form_valid(self, form):
        response = super().form_valid(form)
        # 使用正确的后端名称
        login(self.request, self.object, backend="users.backends.CustomAuthBackend")
        return HttpResponseRedirect(self.object.get_absolute_url())

class AgentLoginView(LoginView):
    template_name = 'users/agent_login.html'
    form_class = AgentSignInForm

    def get_success_url(self):
        # 登录成功后self.request.user已为Agent实例
        return reverse_lazy('agent-dashboard', kwargs={'slug': self.request.user.slug})

5. AgentManager的create_user方法参数与模型字段不匹配

原AgentManager的create_user接收email参数,但Agent模型中对应字段为agent_email,导致创建超级用户出错。

修复models.py中的AgentManager:

class AgentManager(BaseUserManager):
    def create_user(self, username, agent_email, password=None, **extra_fields):
        if not agent_email:
            raise ValueError('The Email field must be set')
        agent_email = self.normalize_email(agent_email)
        user = self.model(username=username, agent_email=agent_email, **extra_fields)
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, username, agent_email, password=None, **extra_fields):
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)
        return self.create_user(username, agent_email, password, **extra_fields)

6. Agent登出视图的无效逻辑

原agent_logout中尝试修改agent.is_authenticated,但该属性是只读属性,无需手动修改。

修复views.py中的agent_logout:

def agent_logout(request):
    logout(request)
    messages.info(request, "")
    return redirect('home')

后续操作

  1. 确保settings.py中已配置AUTH_USER_MODEL = 'users.CustomUser'
  2. 运行python manage.py makemigrations和python manage.py migrate同步模型变更
  3. 测试登录时可在authenticate方法中添加print语句,排查用户查询及密码验证结果

内容的提问来源于stack exchange,提问作者sasuke

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 00:15:55