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

使用自定义认证后端及模型时Django无法正常登录的问题排查

Django自定义认证后端返回有效User实例但登录后仍被重定向回登录页

问题背景

对接已有数据库,原有用户表结构与Django默认User差异极大,通过inspectdb生成非托管模型(managed=False),无法继承AbstractUser,因此采用自定义认证后端+Profile关联模型方案:

  • 自定义后端验证原有CustomUser的用户名密码
  • 验证通过后,通过关联模型Profile获取或创建Django原生User实例并返回

异常现象

  • 自定义authenticate()方法可正常返回有效User实例,无效凭证会正确提示"Invalid Credentials"
  • 登录后始终被重定向回登录页,无法访问受保护资源;使用原生User登录则完全正常
  • 检查request.session和request.user均已被设置,问题疑似出在django.contrib.auth.login环节

相关代码

settings.py中的认证后端配置

AUTHENTICATION_BACKENDS = [
    'Authentication.custom.CustomAuth',
    'django.contrib.auth.backends.ModelBackend'
]

自定义认证后端的authenticate()方法

def authenticate(self, request, username=None, password=None):
    try:
        c_user = CustomUser.objects.get(username=username)
    except CustomUser.DoesNotExist:
        return None
        
    #pwd_valid = check_password(password, user.password)
    if not c_user.password==password:
        return None
    
    #Get and return the django user object
    try:
        profile = Profile.objects.get(custom_user=c_user)
        user = profile.user
        #Create user if profile has none
        if not user:
            user = User.objects.create(
                username=''.join(secrets.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(24))
            )
            profile.user = user
            profile.save()
    #Create new profile if none exists        
    except Profile.DoesNotExist:
        #Create new user for the profile    
        user = User.objects.create(
            username=''.join(secrets.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(24))
        )    
          
        Profile.objects.create(
            user = user,
            custom_user = c_user
        )
    return user

可能的原因及修复方案

1. 未实现get_user()方法(核心问题)

继承BaseBackend时,必须同时覆写authenticate()和get_user()方法。Django登录后会通过get_user()根据用户ID重新获取实例,若未实现该方法,会导致后续认证验证失败,从而被重定向回登录页。

修复代码:在CustomAuth类中添加以下方法:

from django.contrib.auth.models import User

def get_user(self, user_id):
    try:
        return User.objects.get(pk=user_id)
    except User.DoesNotExist:
        return None

2. 密码验证逻辑不安全且可能失效

当前直接对比明文密码c_user.password==password,若原有数据库的密码是哈希存储的,该判断会直接失败,同时明文对比存在极大安全风险。

修复代码:使用Django内置的密码哈希验证方法:

from django.contrib.auth.hashers import check_password

# 替换原有的密码判断逻辑
if not check_password(password, c_user.password):
    return None

3. Profile关联逻辑优化(可选)

若Profile与User是OneToOneField关联,profile.user不会返回None,只会抛出DoesNotExist异常,因此if not user:的判断可以移除,避免无效逻辑。

4. 会话保存确认(排查用)

虽然Django默认会自动保存会话,但可在登录视图中手动触发保存,确保会话数据持久化:

from django.contrib.auth import login

def login_view(request):
    # 认证逻辑...
    login(request, user)
    request.session.save()  # 手动触发会话保存
    # 重定向逻辑...

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 18:50:41