DRF双自定义用户模型:无关联时SimpleJWT生成JWT报错解决
解决办法
1. 确保BogUser模型满足JWT基础要求
BogUser必须继承AbstractBaseUser并实现核心认证字段与方法,让它具备JWT所需的密码哈希、活跃状态等属性:
from django.db import models from django.contrib.auth.models import AbstractBaseUser, BaseUserManager class BogUserManager(BaseUserManager): def create_user(self, email, password=None, **extra_fields): if not email: raise ValueError('必须填写邮箱字段') email = self.normalize_email(email) user = self.model(email=email, **extra_fields) user.set_password(password) user.save(using=self._db) return user class BogUser(AbstractBaseUser): email = models.EmailField(unique=True) full_name = models.CharField(max_length=255) is_active = models.BooleanField(default=True) objects = BogUserManager() USERNAME_FIELD = 'email' REQUIRED_FIELDS = ['full_name'] def __str__(self): return self.email
2. 自定义JWT序列化器支持多用户模型
默认的TokenObtainPairSerializer只识别settings.AUTH_USER_MODEL指定的模型,我们需要自定义序列化器,通过请求中的user_type参数区分登录的用户类型:
from rest_framework import serializers from rest_framework_simplejwt.serializers import TokenObtainPairSerializer from .models import BogUser, CustomUser class MultiUserTokenObtainPairSerializer(TokenObtainPairSerializer): @classmethod def get_token(cls, user): token = super().get_token(user) # 给Token添加自定义标识,区分用户类型 token['user_type'] = 'bog_user' if isinstance(user, BogUser) else 'custom_user' return token def validate(self, attrs): user_type = self.context['request'].data.get('user_type') username = attrs.get(self.username_field) password = attrs.get('password') user = None if user_type == 'bog_user': # 验证BogUser try: user = BogUser.objects.get(email=username) if not user.check_password(password) or not user.is_active: user = None except BogUser.DoesNotExist: pass else: # 验证默认的CustomUser from django.contrib.auth import authenticate user = authenticate( request=self.context.get('request'), username=username, password=password ) if not user: raise serializers.ValidationError('无效的登录凭证') attrs['user'] = user return super().validate(attrs)
3. 替换JWT视图使用自定义序列化器
创建新的Token获取视图,绑定上面的自定义序列化器:
from rest_framework_simplejwt.views import TokenObtainPairView from .serializers import MultiUserTokenObtainPairSerializer class MultiUserTokenObtainPairView(TokenObtainPairView): serializer_class = MultiUserTokenObtainPairSerializer
然后在项目的urls.py中配置这个视图:
path('api/token/', MultiUserTokenObtainPairView.as_view(), name='token_obtain_pair'),
4. 可选:配置多用户认证后端
如果希望Django的authenticate方法能自动识别两个用户模型,可以添加自定义认证后端:
from django.contrib.auth.backends import BaseBackend from .models import CustomUser, BogUser class MultiUserAuthBackend(BaseBackend): def authenticate(self, request, username=None, password=None, **kwargs): # 先尝试CustomUser try: user = CustomUser.objects.get(username=username) if user.check_password(password): return user except CustomUser.DoesNotExist: # 再尝试BogUser try: user = BogUser.objects.get(email=username) if user.check_password(password): return user except BogUser.DoesNotExist: return None def get_user(self, user_id): # 根据ID匹配对应模型的用户 try: return CustomUser.objects.get(pk=user_id) except CustomUser.DoesNotExist: try: return BogUser.objects.get(pk=user_id) except BogUser.DoesNotExist: return None
最后在settings.py中添加这个后端:
AUTHENTICATION_BACKENDS = [ 'yourapp.backends.MultiUserAuthBackend', 'django.contrib.auth.backends.ModelBackend', ]
核心说明
- 全程无需建立两个用户模型的关联,通过
user_type参数或认证后端的匹配逻辑区分不同用户类型的登录请求。 - 自定义序列化器重写了Token生成与验证逻辑,确保BogUser能生成合法的JWT Token。
- 建议给两个用户模型使用UUID作为主键,避免ID重叠导致的用户匹配错误。
内容的提问来源于stack exchange,提问作者Rafaell444
相关产品推荐
相关产品推荐

