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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 01:42:22