Django REST Framework中MongoDB与JWT集成失败问题排查
解决MongoEngine + Django REST Framework + Simple JWT的ObjectId认证问题
问题根源在于Simple JWT默认会将Token中的用户ID当作整数处理,但MongoDB的ObjectId是字符串格式,导致权限校验时查询用户出现类型不匹配错误。以下是具体解决步骤:
1. 确认CustomUser模型正确配置ObjectId主键
确保自定义用户模型使用ObjectIdField作为主键,并正确实现Django用户模型所需的核心方法与字段:
from mongoengine import Document, ObjectIdField, StringField, EmailField from django.contrib.auth.models import AbstractBaseUser, BaseUserManager class CustomUserManager(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 def create_superuser(self, email, password=None, **extra_fields): extra_fields.setdefault('is_staff', True) extra_fields.setdefault('is_superuser', True) return self.create_user(email, password, **extra_fields) class CustomUser(Document, AbstractBaseUser): id = ObjectIdField(primary_key=True) email = EmailField(unique=True) username = StringField(max_length=255, unique=True) is_active = StringField(default=True) is_staff = StringField(default=False) is_superuser = StringField(default=False) USERNAME_FIELD = 'email' REQUIRED_FIELDS = ['username'] objects = CustomUserManager() def has_perm(self, perm, obj=None): return self.is_superuser def has_module_perms(self, app_label): return self.is_superuser
2. 自定义JWT认证后端,适配ObjectId
重写Simple JWT的认证逻辑,修改get_user方法,将Token中的字符串ID转为MongoDB的ObjectId进行查询:
# 在myapp下新建auth_backends.py文件 from rest_framework_simplejwt.authentication import JWTAuthentication from bson.objectid import ObjectId from django.contrib.auth import get_user_model User = get_user_model() class MongoJWTAuthentication(JWTAuthentication): def get_user(self, validated_token): user_id = validated_token['user_id'] try: return User.objects.get(id=ObjectId(user_id)) except User.DoesNotExist: return None
3. 更新配置文件,替换默认认证类
修改settings.py中的REST_FRAMEWORK配置,使用自定义的认证后端:
INSTALLED_APPS = [ # 其他已安装应用 'rest_framework', 'rest_framework_simplejwt', 'myapp', ] AUTH_USER_MODEL = 'myapp.CustomUser' REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': [ 'myapp.auth_backends.MongoJWTAuthentication', # 替换为自定义认证类的路径 ], } SIMPLE_JWT = { 'AUTH_HEADER_TYPES': ('Bearer',), 'USER_ID_FIELD': 'id', 'USER_ID_CLAIM': 'user_id', }
验证效果
你的GetUsersAPI无需修改,配置完成后即可正常使用IsAuthenticated权限:
from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import status from rest_framework.permissions import IsAuthenticated class GetUsersAPI(APIView): permission_classes = [IsAuthenticated] def get(self, request): return Response(status=status.HTTP_200_OK)
以上修改后,JWT认证时会正确处理MongoDB的ObjectId格式用户ID,解决类型不匹配导致的报错。
内容的提问来源于stack exchange,提问作者Mayank
相关产品推荐
相关产品推荐

