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

Apache2/Ubuntu服务器上Django用户Token认证失败问题排查

Token认证失败:"认证凭据未提供"故障排查与解决

问题背景

我正在开发对接安卓应用的Django REST Framework API,已配置端点、视图、模型、序列化器及settings.py,通过自定义命令创建了带Token的超级用户。但使用curl或Postman携带Token访问/usuario-actual/接口时,返回**"认证凭据未提供"**的错误,参照教程及GPT4协助后仍未解决。


现有配置代码

端点配置

from django.urls import path, include
from .views import UserViewSet, UserProfileViewSet, CurrentUserView,LoginView 

urlpatterns = [
    path('usuarios/', UserViewSet.as_view(), name='usuarios'),
    path('usuarios-perfil/', UserProfileViewSet.as_view(), name='usuarios-perfil'),
    path('usuario-actual/', CurrentUserView.as_view(), name='usuario-actual'),
    path('login/', LoginView.as_view(), name='login'),
]

视图配置

from rest_framework import generics
from django.contrib.auth.models import User
from .models import UserProfile
from .serializers import UserSerializer, UserProfileSerializer
from rest_framework.permissions import IsAuthenticated
from django.contrib.auth import get_user_model
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
import logging

logger = logging.getLogger(__name__)

class UserViewSet(generics.ListCreateAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer

class UserProfileViewSet(generics.ListCreateAPIView):
    queryset = UserProfile.objects.all()
    serializer_class = UserProfileSerializer

class CurrentUserView(generics.RetrieveAPIView):
    permission_classes = (IsAuthenticated,) 
    serializer_class = UserSerializer
    def get_object(self):
        logger.info(self.request.META)
        logger.debug(f"CurrentUserView.get_object called for user {self.request.user}")
        return self.request.user
def authenticate(email=None, password=None):
    UserModel = get_user_model()
    try:
        user = UserModel.objects.get(email=email)
    except UserModel.DoesNotExist:
        return None

    if user.check_password(password):
        return user

# En tu LoginView
class LoginView(APIView):
    def post(self, request, format=None):
        user = authenticate(email=request.data.get('email'), password=request.data.get('password'))
        if user is not None:
            token, created = Token.objects.get_or_create(user=user)
            return Response({'token': token.key})
        else:
            return Response(status=401)

模型配置

from django.db import models
from django.contrib.auth.models import User

class UserProfile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    is_premium = models.BooleanField(default=False)

    def __str__(self):
        return self.user.username

序列化器配置

from rest_framework import serializers
from django.contrib.auth.models import User
from .models import UserProfile

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['username', 'is_staff']

class UserProfileSerializer(serializers.ModelSerializer):
    user = UserSerializer()

    class Meta:
        model = UserProfile
        fields = ['user', 'is_premium']

settings.py关键配置

INSTALLED_APPS = [
    ...
    'rest_framework', 
    'rest_framework.authtoken',
]

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.TokenAuthentication',
    ]
}

超级用户创建命令

from django.core.management.base import BaseCommand
from django.contrib.auth.models import User
from api_es.models import UserProfile
from rest_framework.authtoken.models import Token  # Asegúrate de que estás importando el modelo Token de aquí

class Command(BaseCommand):
    help = 'Crea un nuevo usuario superusuario'

    def handle(self, *args, **options):
        username = 'lolo'
        password = 'AdGj2727'
        email = 'quizandguide@gmail.com'

        # Crear una nueva instancia de User y guardarla
        user = User(username=username, email=email, is_active=True, is_superuser=True, is_staff=True)
        user.set_password(password)
        user.save()

        # Crear una nueva instancia de UserProfile y guardarla
        user_profile = UserProfile(user=user, is_premium=True)
        user_profile.save()

        # Crear un token para el usuario
        token = Token.objects.create(user=user)

        self.stdout.write(self.style.SUCCESS('Superusuario creado exitosamente.'))

请求示例与错误返回

curl -H "Authorization: Token e65905ad748d67f127929c14d3a78b9de8300c51" https://football-quiz-and-guide.com/es/usuario-actual/

返回错误:

{"detail":"Las credenciales de autenticación no se proveyeron."}

翻译:认证凭据未提供


故障原因及解决办法

1. 自定义authenticate函数覆盖内置方法

视图中自定义的authenticate函数覆盖了Django自带的django.contrib.auth.authenticate方法,导致DRF的Token认证流程无法调用正确的认证逻辑。

解决办法:
重命名自定义认证函数,避免冲突:

# 修改函数名
def authenticate_by_email(email=None, password=None):
    UserModel = get_user_model()
    try:
        user = UserModel.objects.get(email=email)
    except UserModel.DoesNotExist:
        return None

    if user.check_password(password):
        return user

# 在LoginView中调用修改后的函数
class LoginView(APIView):
    def post(self, request, format=None):
        user = authenticate_by_email(email=request.data.get('email'), password=request.data.get('password'))
        # 后续逻辑不变

2. 视图未显式指定认证类

全局默认认证类可能未被视图正确继承,需显式指定认证方式。

解决办法:
在CurrentUserView中添加authentication_classes配置:

class CurrentUserView(generics.RetrieveAPIView):
    permission_classes = (IsAuthenticated,) 
    # 显式指定Token认证类
    authentication_classes = ['rest_framework.authentication.TokenAuthentication']
    serializer_class = UserSerializer
    def get_object(self):
        logger.info(self.request.META)
        logger.debug(f"CurrentUserView.get_object called for user {self.request.user}")
        return self.request.user

3. 请求头格式错误

curl命令中的转义引号会导致请求头解析失败,服务器无法识别Authorization字段。

解决办法:
修改curl命令,去掉转义引号:

# Linux/macOS环境
curl -H "Authorization: Token e65905ad748d67f127929c14d3a78b9de8300c51" https://football-quiz-and-guide.com/es/usuario-actual/

# Windows命令行环境
curl -H 'Authorization: Token e65905ad748d67f127929c14d3a78b9de8300c51' https://football-quiz-and-guide.com/es/usuario-actual/

4. 中间件配置缺失

缺少AuthenticationMiddleware会导致DRF无法处理用户认证会话。

解决办法:
检查settings.py的MIDDLEWARE配置,确保包含:

MIDDLEWARE = [
    ...
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    ...
]

5. Token有效性验证

确认Token与用户正确关联,未被篡改或删除。

解决办法:
通过Django Shell验证Token:

from rest_framework.authtoken.models import Token
token = Token.objects.get(key='e65905ad748d67f127929c14d3a78b9de8300c51')
print(token.user.username)  # 应输出'lolo'

若Token不存在,重新生成:

from django.contrib.auth.models import User
from rest_framework.authtoken.models import Token
user = User.objects.get(username='lolo')
Token.objects.create(user=user)

内容的提问来源于stack exchange,提问作者user22258284

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 16:17:11