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
相关产品推荐
相关产品推荐

