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

Django Token认证异常:凭证正确却无法生成Token并返回错误

问题排查与解决思路

1. 确认自定义User模型的USERNAME_FIELD配置

如果你的User模型是自定义的(非Django默认用户模型),必须在模型类中指定USERNAME_FIELD = 'email',让Django认证系统将邮箱作为用户唯一标识:

class User(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(unique=True)
    # 其他自定义字段...
    USERNAME_FIELD = 'email'  # 关键配置
    REQUIRED_FIELDS = []  # 根据业务需求添加必填字段

若缺少该配置,默认的ModelBackend会尝试用username字段认证,你传入的email参数无法被识别,直接导致authenticate()返回None。

2. 检查认证后端配置

确保settings.py中的AUTHENTICATION_BACKENDS包含支持邮箱认证的后端:

  • 若已设置USERNAME_FIELD = 'email',保留默认后端即可:
AUTHENTICATION_BACKENDS = [
    'django.contrib.auth.backends.ModelBackend',
]
  • 若未修改USERNAME_FIELD,需自定义认证后端支持邮箱登录:
# 在你的app下创建backends.py
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth import get_user_model
from django.db.models import Q

UserModel = get_user_model()

class EmailBackend(ModelBackend):
    def authenticate(self, request, username=None, password=None, **kwargs):
        try:
            user = UserModel.objects.get(Q(email=username))
        except UserModel.DoesNotExist:
            UserModel().set_password(password)
            return None
        except UserModel.MultipleObjectsReturned:
            user = UserModel.objects.filter(Q(email=username)).first()

        if user.check_password(password) and self.user_can_authenticate(user):
            return user

然后在settings.py中配置:

AUTHENTICATION_BACKENDS = [
    'your_app.backends.EmailBackend',
    'django.contrib.auth.backends.ModelBackend',
]

3. 验证密码存储合法性

确认数据库中用户密码是哈希值而非明文:

  • 进入Django Shell:python manage.py shell
  • 执行验证:
from your_app.models import User
user = User.objects.get(email='测试邮箱')
print(user.check_password('测试密码'))  # 返回True才正常

若返回False,说明创建用户时未正确调用set_password,需检查UserSerializer的create方法是否被正确执行。

4. 调整LoginAPIView逻辑顺序

先验证请求数据合法性,再执行认证操作,同时给authenticate传入request参数:

class LoginAPIView(views.APIView):
    def post(self, request):
        serializer = LoginSerializer(data=request.data)
        if serializer.is_valid():
            email = serializer.validated_data["email"]
            password = serializer.validated_data["password"]
            # 若用自定义EmailBackend,这里username参数传邮箱;若设置了USERNAME_FIELD='email',也可直接用email参数
            user = authenticate(request=request, username=email, password=password)
            if user is not None:
                token, created = Token.objects.get_or_create(user=user)
                return Response({
                    'data': serializer.data,
                    'token': token.key
                })
            else:
                return Response({
                    'errors': 'Invalid email or password.'
                }, status=400)
        else:
            return Response(serializer.errors, status=400)

5. 完善LoginSerializer字段配置

给password字段添加write_only=True,避免密码哈希值在响应中返回:

class LoginSerializer(serializers.ModelSerializer):
    password = serializers.CharField(write_only=True)
    
    class Meta:
        model = User
        fields = ['email', 'password']

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 19:05:04