Django Rest Framework TokenAuthentication报错‘Invalid Token’求助
问题排查与解决方案
核心原因
DRF默认的TokenAuthentication和Django认证系统默认依赖username字段,但你的CustomUser用email替代了username作为用户唯一标识,若未正确配置相关参数,会导致Token验证时无法匹配到用户。
具体排查步骤与修复
1. 确认CustomUser模型配置正确
确保自定义用户模型明确指定email作为唯一标识字段:
# users/models.py from django.contrib.auth.models import AbstractUser from django.db import models class CustomUser(AbstractUser): username = None # 移除默认username字段 email = models.EmailField(verbose_name='邮箱', unique=True) # 关键配置:指定email作为用户认证的唯一标识 USERNAME_FIELD = 'email' # 若无需其他必填字段,设为空列表 REQUIRED_FIELDS = [] def __str__(self): return self.email
配置后运行迁移:
python manage.py makemigrations python manage.py migrate
2. 检查登录视图的认证逻辑
登录时调用authenticate方法必须使用USERNAME_FIELD对应的参数名(即email),而非默认的username:
# users/views.py from django.contrib.auth import authenticate from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.authtoken.models import Token from django.contrib.auth import get_user_model User = get_user_model() class LoginView(APIView): permission_classes = [] # 允许未登录访问 def post(self, request): email = request.data.get('email') password = request.data.get('password') # 正确写法:使用USERNAME_FIELD动态获取参数名 user = authenticate( request, **{User.USERNAME_FIELD: email, 'password': password} ) if user and user.is_active: token, _ = Token.objects.get_or_create(user=user) return Response({'token': token.key}) return Response({'detail': '无效的登录凭据'}, status=400)
3. 验证Token关联的用户状态
检查数据库中authtoken_token表对应的user_id是否存在,且该用户的is_active字段为True。若用户被标记为非活跃,Token验证会直接失败。
4. (可选)自定义TokenAuthentication类
若上述步骤仍未解决问题,可自定义认证类确保验证逻辑适配email字段:
# users/authentication.py from rest_framework.authtoken.authentication import TokenAuthentication from rest_framework.authtoken.models import Token from django.contrib.auth import get_user_model User = get_user_model() class EmailTokenAuthentication(TokenAuthentication): def authenticate_credentials(self, key): try: # 关联查询用户,避免额外数据库请求 token = Token.objects.select_related('user').get(key=key) except Token.DoesNotExist: return None # 验证用户是否活跃 if not token.user.is_active: return None return (token.user, token)
然后在settings.py中替换默认认证类:
# settings.py REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': [ 'users.authentication.EmailTokenAuthentication', # 自定义类 # 'rest_framework.authentication.TokenAuthentication', # 注释掉默认类 ] }
测试验证
在测试用例中确保请求头格式正确:
# goals/tests.py from django.test import TestCase from rest_framework.test import APIClient from django.contrib.auth import get_user_model User = get_user_model() class TopicTestCase(TestCase): def setUp(self): self.client = APIClient() self.user = User.objects.create_user(email='test@example.com', password='123456') # 获取Token response = self.client.post('/api/login/', {'email': 'test@example.com', 'password': '123456'}) self.token = response.data['token'] def test_create_topic(self): # 设置请求头 self.client.credentials(HTTP_AUTHORIZATION='Token ' + self.token) response = self.client.post('/api/goals/topics/', {'name': '测试主题'}) self.assertEqual(response.status_code, 201)
内容的提问来源于stack exchange,提问作者William
相关产品推荐
相关产品推荐

