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

simple-jwt登录验证失败:无有效账户错误排查求助

解决Simple-JWT自定义User模型登录报错问题

问题现象

自定义User模型支持邮箱/手机号登录,但集成simple-jwt时持续返回:

{
"detail": "No active account found with the given credentials"
}

已确认账户为激活状态,尝试过新创建的超级用户,问题仍存在。

代码问题分析与修复

1. models.py 错误修复

  • 重复定义password字段:AbstractBaseUser已内置password字段,自定义User中重复定义会导致set_password()无法正确加密存储密码,需删除该字段。
  • 无用代码冗余:create_user方法中user = self.normalize_email(email)属于无效赋值,需删除并在model初始化时正确处理邮箱格式化。

修改后的models.py核心代码:

class CustomUserManager(BaseUserManager):
    def create_user(self, name, email, phone_number, password, **other_fields):
        if not phone_number:
            raise ValueError('You must provide a phone number')
        # 正确格式化邮箱并初始化用户
        user = self.model(email=self.normalize_email(email), name=name, phone_number=phone_number, **other_fields)
        user.set_password(password)
        user.save()
        return user
    
    # 超级用户创建方法保持不变...


class User(AbstractBaseUser, PermissionsMixin):
    name = models.CharField(max_length=200)
    email = models.EmailField(unique=True, null=True)
    phone_number = models.CharField(max_length=50, unique=True)
    # 移除重复定义的password字段
    is_staff = models.BooleanField(default=False)
    is_active = models.BooleanField(default=False)

    objects = CustomUserManager()

    USERNAME_FIELD = 'phone_number'
    REQUIRED_FIELDS =['name', 'email']

    def __str__(self):
        return self.name

2. backends.py 认证逻辑修复

  • 缺少用户活跃状态检查:authenticate方法未验证user.is_active,与simple-jwt默认认证规则冲突,需添加该检查。
  • 冗余try-except嵌套:用Q对象合并邮箱/手机号查询逻辑,简化代码结构。

修改后的backends.py代码:

from django.contrib.auth.backends import ModelBackend
from django.contrib.auth import get_user_model
from django.db.models import Q

class EmailOrPhoneNumberBackend(ModelBackend):
    def authenticate(self, request, username=None, password=None, **kwargs):
        UserModel = get_user_model()
        try:
            # 用Q对象同时匹配邮箱或手机号
            user = UserModel.objects.get(Q(email=username) | Q(phone_number=username))
        except UserModel.DoesNotExist:
            return None

        # 同时验证密码正确性与用户活跃状态
        if user.check_password(password) and user.is_active:
            return user

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

3. settings.py 配置优化

SIMPLE_JWT中USER_ID_FIELD建议使用主键id(默认值),而非phone_number,避免字符串作为用户ID带来的潜在问题:

SIMPLE_JWT = {
    'AUTH_HEADER_TYPES': ('Bearer',),
    'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION',
    'USER_ID_FIELD': 'id',  # 改为主键字段
    'USER_ID_CLAIM': 'user_id',
    'USER_AUTHENTICATION_RULE': 'rest_framework_simplejwt.authentication.default_user_authentication_rule',
}

后续操作

  1. 执行数据库迁移:python manage.py makemigrations && python manage.py migrate
  2. 重新创建测试用户/超级用户:python manage.py createsuperuser(确保新用户密码被正确加密)
  3. 再次调用simple-jwt的登录接口,使用邮箱或手机号作为username参数,即可正常获取Token。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 17:53:11