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

djangorestframework-simplejwt自定义用户模型报无有效账户错误怎么办

认证失败根因

所有问题的核心是密码未经过哈希就存入了数据库,和JWT配置、用户类型字段无关:

  • 用createsuperuser创建的超级用户能正常登录,是因为该命令内部会自动对密码做哈希处理,符合Django的认证校验逻辑。
  • 通过Admin后台、fixtures创建的用户登录失败,是因为这两种场景下写入数据库的密码都是明文,和认证时传入的密码哈希结果无法匹配,触发认证失败。
  • 当前序列化器逻辑没有处理密码哈希,后续通过接口创建的用户同样会出现登录失败问题。
修复方案

1. 修正Admin后台的用户注册逻辑

不要直接用默认ModelAdmin注册自定义User模型,改用Django内置的UserAdmin,自动复用密码哈希、权限校验等内置逻辑。
修改后的admin.py完整代码:

from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from .models import User, UserType1, UserType2

# 继承内置UserAdmin,自动保留密码哈希等核心逻辑
class UserAdmin(BaseUserAdmin):
    # 把自定义的用户类型字段加入Admin展示,按需调整
    fieldsets = BaseUserAdmin.fieldsets + (
        ('平台用户类型', {'fields': ('is_user_type_1', 'is_user_type_2')}),
    )

admin.site.register(User, UserAdmin)
admin.site.register(UserType1)
admin.site.register(UserType2)

2. 修正序列化器的密码处理逻辑

重写UserSerializer的创建、更新方法,确保密码入库前自动哈希:

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = (
            'username',
            'email',
            'password',
            'first_name',
            'last_name',
            'is_active',
        )
        extra_kwargs = {"password": {"write_only": True, "required": True}}

    def create(self, validated_data):
        # 调用内置create_user方法,自动处理密码哈希
        return User.objects.create_user(**validated_data)

    def update(self, instance, validated_data):
        # 处理密码修改场景的哈希逻辑
        password = validated_data.pop("password", None)
        user = super().update(instance, validated_data)
        if password:
            user.set_password(password)
            user.save()
        return user

同时简化UserType1Serializer、UserType2Serializer的创建逻辑,把用户类型标记直接合并到用户参数里:

class UserType1Serializer(serializers.ModelSerializer):
    user = UserSerializer(required=True)

    class Meta:
        model = UserType1
        fields = ('user', 'created', 'modified')

    @transaction.atomic
    def create(self, validated_data):
        user_data = validated_data.pop('user')
        # 直接合并用户类型标记
        user_data.update({
            "is_user_type_1": True,
            "is_user_type_2": False
        })
        user = UserSerializer().create(validated_data=user_data)
        user_type_1, _ = UserType1.objects.update_or_create(user=user)
        return user_type_1

UserType2Serializer做对应逻辑修改即可。

3. 修正fixtures的密码导入逻辑

如果需要通过fixtures导入用户,不能直接在fixture文件里写明文密码,需要先生成哈希后的密码值再写入:

  • 运行python manage.py shell,执行以下代码生成哈希密码:
    from django.contrib.auth.hashers import make_password
    print(make_password("你的明文密码"))
    
  • 把输出的哈希字符串填入fixture的password字段,导入后即可正常认证。

4. 额外校验项

  • 确认导入、创建的普通用户is_active字段为True,Django默认拒绝未激活用户的认证请求。
  • 确认JWT认证的后端配置正常,没有自定义逻辑错误过滤普通用户。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.26 18:54:03